15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""PyAuto: Python Interface to Chromium's Automation Proxy.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PyAuto uses swig to expose Automation Proxy interfaces to Python.
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)For complete documentation on the functionality available,
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)run pydoc on this file.
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Ref: http://dev.chromium.org/developers/testing/pyauto
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Include the following in your PyAuto test script to make it run standalone.
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from pyauto import Main
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Main()
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This script can be used as an executable to fire off other scripts, similar
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)to unittest.py
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  python pyauto.py test_script
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import cStringIO
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import copy
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import functools
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import hashlib
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import inspect
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import optparse
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import pickle
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import pprint
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import shutil
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import signal
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import socket
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import stat
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import string
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import tempfile
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import time
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import types
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import unittest
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import urllib
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import pyauto_paths
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _LocateBinDirs():
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Setup a few dirs where we expect to find dependency libraries."""
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  deps_dirs = [
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.path.dirname(__file__),
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_paths.GetThirdPartyDir(),
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.path.join(pyauto_paths.GetThirdPartyDir(), 'webdriver', 'pylib'),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ]
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.path += map(os.path.normpath, pyauto_paths.GetBuildDirs() + deps_dirs)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_LocateBinDirs()
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_PYAUTO_DOC_URL = 'http://dev.chromium.org/developers/testing/pyauto'
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)try:
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  import pyautolib
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Needed so that all additional classes (like: FilePath, GURL) exposed by
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # swig interface get available in this module.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  from pyautolib import *
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)except ImportError:
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print >>sys.stderr, 'Could not locate pyautolib shared libraries.  ' \
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      'Did you build?\n  Documentation: %s' % _PYAUTO_DOC_URL
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Mac requires python2.5 even when not the default 'python' (e.g. 10.6)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if 'darwin' == sys.platform and sys.version_info[:2] != (2,5):
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print  >>sys.stderr, '*\n* Perhaps use "python2.5", not "python" ?\n*'
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  raise
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Should go after sys.path is set appropriately
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import bookmark_model
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import download_info
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import history_info
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import omnibox_info
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import plugins_info
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import prefs_info
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from pyauto_errors import AutomationCommandFail
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from pyauto_errors import AutomationCommandTimeout
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from pyauto_errors import JavascriptRuntimeError
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from pyauto_errors import JSONInterfaceError
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from pyauto_errors import NTPThumbnailNotShownError
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import pyauto_utils
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import simplejson as json  # found in third_party
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_CHROME_DRIVER_FACTORY = None
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_DEFAULT_AUTOMATION_TIMEOUT = 45
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_HTTP_SERVER = None
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_REMOTE_PROXY = None
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_OPTIONS = None
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_BROWSER_PID = None
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Base class for UI Test Cases in Python.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  A browser is created before executing each test, and is destroyed after
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  each test irrespective of whether the test passed or failed.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  You should derive from this class and create methods with 'test' prefix,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  and use methods inherited from PyUITestBase (the C++ side).
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Example:
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    class MyTest(PyUITest):
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      def testNavigation(self):
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.NavigateToURL("http://www.google.com")
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.assertEqual("Google", self.GetActiveTabTitle())
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, methodName='runTest', **kwargs):
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Initialize PyUITest.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    When redefining __init__ in a derived class, make sure that:
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      o you make a call this __init__
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      o __init__ takes methodName as an arg. this is mandated by unittest module
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      methodName: the default method name. Internal use by unittest module
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (The rest of the args can be in any order. They can even be skipped in
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       which case the defaults will be used.)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      clear_profile: If True, clean the profile dir before use. Defaults to True
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      homepage: the home page. Defaults to "about:blank"
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Fetch provided keyword args, or fill in defaults.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clear_profile = kwargs.get('clear_profile', True)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    homepage = kwargs.get('homepage', 'about:blank')
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._automation_timeout = _DEFAULT_AUTOMATION_TIMEOUT * 1000
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pyautolib.PyUITestBase.__init__(self, clear_profile, homepage)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.Initialize(pyautolib.FilePath(self.BrowserPath()))
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unittest.TestCase.__init__(self, methodName)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Give all pyauto tests easy access to pprint.PrettyPrinter functions.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.pprint = pprint.pprint
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.pformat = pprint.pformat
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Set up remote proxies, if they were requested.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.remotes = []
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.remote = None
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global _REMOTE_PROXY
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if _REMOTE_PROXY:
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.remotes = _REMOTE_PROXY
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.remote = _REMOTE_PROXY[0]
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __del__(self):
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pyautolib.PyUITestBase.__del__(self)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _SetExtraChromeFlags(self):
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Prepares the browser to launch with the specified extra Chrome flags.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This function is called right before the browser is launched for the first
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    time.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for flag in self.ExtraChromeFlags():
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if flag.startswith('--'):
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        flag = flag[2:]
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      split_pos = flag.find('=')
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if split_pos >= 0:
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        flag_name = flag[:split_pos]
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        flag_val = flag[split_pos + 1:]
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.AppendBrowserLaunchSwitch(flag_name, flag_val)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.AppendBrowserLaunchSwitch(flag)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __SetUp(self):
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    named_channel_id = None
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if _OPTIONS:
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      named_channel_id = _OPTIONS.channel_id
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.IsChromeOS():  # Enable testing interface on ChromeOS.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self.get_clear_profile():
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.CleanupBrowserProfileOnChromeOS()
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.EnableCrashReportingOnChromeOS()
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not named_channel_id:
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        named_channel_id = self.EnableChromeTestingOnChromeOS()
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._SetExtraChromeFlags()  # Flags already previously set for ChromeOS.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if named_channel_id:
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._named_channel_id = named_channel_id
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.UseNamedChannelID(named_channel_id)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Initialize automation and fire the browser (does not fire the browser
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # on ChromeOS).
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetUp()
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global _BROWSER_PID
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      _BROWSER_PID = self.GetBrowserInfo()['browser_pid']
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except JSONInterfaceError:
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise JSONInterfaceError('Unable to get browser_pid over automation '
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               'channel on first attempt.  Something went very '
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               'wrong.  Chrome probably did not launch.')
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Forcibly trigger all plugins to get registered.  crbug.com/94123
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Sometimes flash files loaded too quickly after firing browser
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # ends up getting downloaded, which seems to indicate that the plugin
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # hasn't been registered yet.
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not self.IsChromeOS():
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.GetPluginsInfo()
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(dtu): Remove this after crosbug.com/4558 is fixed.
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.IsChromeOS():
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.WaitUntil(lambda: not self.GetNetworkInfo()['offline_mode'])
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (self.IsChromeOS() and not self.GetLoginInfo()['is_logged_in'] and
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.ShouldOOBESkipToLogin()):
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self.GetOOBEScreenInfo()['screen_name'] != 'login':
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.SkipToLogin()
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self.ShouldAutoLogin():
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Login with default creds.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys.path.append('/usr/local')  # to import autotest libs
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        from autotest.cros import constants
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        creds = constants.CREDENTIALS['$default']
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.Login(creds[0], creds[1])
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        assert self.GetLoginInfo()['is_logged_in']
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.info('Logged in as %s.' % creds[0])
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # If we are connected to any RemoteHosts, create PyAuto
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # instances on the remote sides and set them up too.
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for remote in self.remotes:
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      remote.CreateTarget(self)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      remote.setUp()
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def setUp(self):
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Override this method to launch browser differently.
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Can be used to prevent launching the browser window by default in case a
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    test wants to do some additional setup before firing browser.
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    When using the named interface, it connects to an existing browser
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    instance.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    On ChromeOS, a browser showing the login window is started. Tests can
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    initiate a user session by calling Login() or LoginAsGuest(). Cryptohome
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    vaults or flimflam profiles left over by previous tests can be cleared by
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    calling RemoveAllCryptohomeVaults() respectively CleanFlimflamDirs() before
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging in to improve isolation. Note that clearing flimflam profiles
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    requires a flimflam restart, briefly taking down network connectivity and
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    slowing down the test. This should be done for tests that use flimflam only.
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.__SetUp()
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def tearDown(self):
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for remote in self.remotes:
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      remote.tearDown()
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.TearDown()  # Destroy browser
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Method required by the Python standard library unittest.TestCase.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def runTest(self):
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pass
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def BrowserPath():
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the path to Chromium binaries.
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Expects the browser binaries to be in the
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    same location as the pyautolib binaries.
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return os.path.normpath(os.path.dirname(pyautolib.__file__))
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExtraChromeFlags(self):
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return a list of extra chrome flags to use with Chrome for testing.
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    These are flags needed to facilitate testing.  Override this function to
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    use a custom set of Chrome flags.
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    auth_ext_path = ('/usr/local/autotest/deps/pyauto_dep/' +
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'test_src/chrome/browser/resources/gaia_auth')
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.IsChromeOS():
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return [
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '--homepage=about:blank',
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '--allow-file-access',
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '--allow-file-access-from-files',
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '--enable-file-cookies',
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '--disable-default-apps',
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '--dom-automation',
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '--skip-oauth-login',
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Enables injection of test content script for webui login automation
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '--auth-ext-path=%s' % auth_ext_path,
291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        # Enable automation provider, chromeos net and chromeos login logs
292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        '--vmodule=*/browser/automation/*=2,*/chromeos/net/*=2,' +
293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            '*/chromeos/login/*=2',
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ]
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return []
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ShouldOOBESkipToLogin(self):
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Determine if we should skip the OOBE flow on ChromeOS.
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This makes automation skip the OOBE flow during setUp() and land directly
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    to the login screen. Applies only if not logged in already.
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Override and return False if OOBE flow is required, for OOBE tests, for
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    example. Calling this function directly will have no effect.
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True, if the OOBE should be skipped and automation should
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            go to the 'Add user' login screen directly
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      False, if the OOBE should not be skipped.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert self.IsChromeOS()
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return True
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ShouldAutoLogin(self):
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Determine if we should auto-login on ChromeOS at browser startup.
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    To be used for tests that expect user to be logged in before running test,
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    without caring which user. ShouldOOBESkipToLogin() should return True
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for this to take effect.
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Override and return False to not auto login, for tests where login is part
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    of the use case.
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True, if chrome should auto login after startup.
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      False, otherwise.
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert self.IsChromeOS()
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return True
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CloseChromeOnChromeOS(self):
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gracefully exit chrome on ChromeOS."""
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _GetListOfChromePids():
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """Retrieves the list of currently-running Chrome process IDs.
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Returns:
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        A list of strings, where each string represents a currently-running
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'chrome' process ID.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc = subprocess.Popen(['pgrep', '^chrome$'], stdout=subprocess.PIPE)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc.wait()
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return [x.strip() for x in proc.stdout.readlines()]
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    orig_pids = _GetListOfChromePids()
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    subprocess.call(['pkill', '^chrome$'])
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _AreOrigPidsDead(orig_pids):
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """Determines whether all originally-running 'chrome' processes are dead.
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Args:
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        orig_pids: A list of strings, where each string represents the PID for
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   an originally-running 'chrome' process.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Returns:
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        True, if all originally-running 'chrome' processes have been killed, or
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        False otherwise.
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for new_pid in _GetListOfChromePids():
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if new_pid in orig_pids:
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return False
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return True
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WaitUntil(lambda: _AreOrigPidsDead(orig_pids))
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _IsRootSuid(path):
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Determine if |path| is a suid-root file."""
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return os.path.isfile(path) and (os.stat(path).st_mode & stat.S_ISUID)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SuidPythonPath():
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Path to suid_python binary on ChromeOS.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is typically in the same directory as pyautolib.py
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return os.path.join(PyUITest.BrowserPath(), 'suid-python')
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RunSuperuserActionOnChromeOS(action):
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Run the given action with superuser privs (on ChromeOS).
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Uses the suid_actions.py script.
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      action: An action to perform.
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              See suid_actions.py for available options.
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stdout, stderr)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert PyUITest._IsRootSuid(PyUITest.SuidPythonPath()), \
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Did not find suid-root python at %s' % PyUITest.SuidPythonPath()
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_path = os.path.join(os.path.dirname(__file__), 'chromeos',
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             'suid_actions.py')
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    args = [PyUITest.SuidPythonPath(), file_path, '--action=%s' % action]
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc = subprocess.Popen(
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stdout, stderr = proc.communicate()
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (stdout, stderr)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def EnableChromeTestingOnChromeOS(self):
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Enables the named automation interface on chromeos.
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Restarts chrome so that you get a fresh instance.
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Also sets some testing-friendly flags for chrome.
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Expects suid python to be present in the same dir as pyautolib.py
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert PyUITest._IsRootSuid(self.SuidPythonPath()), \
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Did not find suid-root python at %s' % self.SuidPythonPath()
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_path = os.path.join(os.path.dirname(__file__), 'chromeos',
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             'enable_testing.py')
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    args = [self.SuidPythonPath(), file_path]
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Pass extra chrome flags for testing
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for flag in self.ExtraChromeFlags():
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      args.append('--extra-chrome-flags=%s' % flag)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert self.WaitUntil(lambda: self._IsSessionManagerReady(0))
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc = subprocess.Popen(args, stdout=subprocess.PIPE)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    automation_channel_path = proc.communicate()[0].strip()
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert len(automation_channel_path), 'Could not enable testing interface'
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return automation_channel_path
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def EnableCrashReportingOnChromeOS():
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Enables crash reporting on ChromeOS.
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Writes the "/home/chronos/Consent To Send Stats" file with a 32-char
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    readable string.  See comment in session_manager_setup.sh which does this
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    too.
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Note that crash reporting will work only if breakpad is built in, ie in a
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'Google Chrome' build (not Chromium).
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consent_file = '/home/chronos/Consent To Send Stats'
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _HasValidConsentFile():
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not os.path.isfile(consent_file):
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return False
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stat = os.stat(consent_file)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return (len(open(consent_file).read()) and
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              (1000, 1000) == (stat.st_uid, stat.st_gid))
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not _HasValidConsentFile():
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_id = hashlib.md5('abcdefgh').hexdigest()
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Consent file creation and chown to chronos needs to be atomic
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # to avoid races with the session_manager.  crosbug.com/18413
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Therefore, create a temp file, chown, then rename it as consent file.
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      temp_file = consent_file + '.tmp'
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      open(temp_file, 'w').write(client_id)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # This file must be owned by chronos:chronos!
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.chown(temp_file, 1000, 1000);
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shutil.move(temp_file, consent_file)
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert _HasValidConsentFile(), 'Could not create %s' % consent_file
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _IsSessionManagerReady(old_pid):
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Is the ChromeOS session_manager running and ready to accept DBus calls?
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Called after session_manager is killed to know when it has restarted.
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      old_pid: The pid that session_manager had before it was killed,
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               to ensure that we don't look at the DBus interface
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               of an old session_manager process.
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pgrep_process = subprocess.Popen(['pgrep', 'session_manager'],
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     stdout=subprocess.PIPE)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_pid = pgrep_process.communicate()[0].strip()
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not new_pid or old_pid == new_pid:
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    import dbus
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bus = dbus.SystemBus()
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proxy = bus.get_object('org.chromium.SessionManager',
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             '/org/chromium/SessionManager')
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dbus.Interface(proxy, 'org.chromium.SessionManagerInterface')
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except dbus.DBusException:
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return True
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CleanupBrowserProfileOnChromeOS():
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Cleanup browser profile dir on ChromeOS.
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This does not clear cryptohome.
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Browser should not be running, or else there will be locked files.
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    profile_dir = '/home/chronos/user'
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for item in os.listdir(profile_dir):
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Deleting .pki causes stateful partition to get erased.
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if item not in ['log', 'flimflam'] and not item.startswith('.'):
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         pyauto_utils.RemovePath(os.path.join(profile_dir, item))
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chronos_dir = '/home/chronos'
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for item in os.listdir(chronos_dir):
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if item != 'user' and not item.startswith('.'):
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pyauto_utils.RemovePath(os.path.join(chronos_dir, item))
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CleanupFlimflamDirsOnChromeOS():
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Clean the contents of flimflam profiles and restart flimflam."""
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PyUITest.RunSuperuserActionOnChromeOS('CleanFlimflamDirs')
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RemoveAllCryptohomeVaultsOnChromeOS():
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Remove any existing cryptohome vaults."""
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PyUITest.RunSuperuserActionOnChromeOS('RemoveAllCryptohomeVaults')
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _IsInodeNew(path, old_inode):
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Determine whether an inode has changed. POSIX only.
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path: The file path to check for changes.
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      old_inode: The old inode number.
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True if the path exists and its inode number is different from old_inode.
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      False otherwise.
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stat_result = os.stat(path)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except OSError:
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not stat_result:
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return stat_result.st_ino != old_inode
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RestartBrowser(self, clear_profile=True, pre_launch_hook=None):
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Restart the browser.
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    For use with tests that require to restart the browser.
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      clear_profile: If True, the browser profile is cleared before restart.
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     Defaults to True, that is restarts browser with a clean
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     profile.
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pre_launch_hook: If specified, must be a callable that is invoked before
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       the browser is started again. Not supported in ChromeOS.
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.IsChromeOS():
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert pre_launch_hook is None, 'Not supported in ChromeOS'
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.TearDown()
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if clear_profile:
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.CleanupBrowserProfileOnChromeOS()
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.CloseChromeOnChromeOS()
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.EnableChromeTestingOnChromeOS()
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.SetUp()
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Not chromeos
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    orig_clear_state = self.get_clear_profile()
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.CloseBrowserAndServer()
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.set_clear_profile(clear_profile)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if pre_launch_hook:
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pre_launch_hook()
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug('Restarting browser with clear_profile=%s',
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  self.get_clear_profile())
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.LaunchBrowserAndServer()
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.set_clear_profile(orig_clear_state)  # Reset to original state.
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def DataDir():
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the path to the data dir chrome/test/data."""
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return os.path.normpath(
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        os.path.join(os.path.dirname(__file__), os.pardir, "data"))
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def ChromeOSDataDir():
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Returns the path to the data dir chromeos/test/data."""
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return os.path.normpath(
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     "chromeos", "test", "data"))
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @staticmethod
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetFileURLForPath(*path):
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get file:// url for the given path.
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Also quotes the url using urllib.quote().
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path: Variable number of strings that can be joined.
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path_str = os.path.join(*path)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    abs_path = os.path.abspath(path_str)
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if sys.platform == 'win32':
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Don't quote the ':' in drive letter ( say, C: ) on win.
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Also, replace '\' with '/' as expected in a file:/// url.
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drive, rest = os.path.splitdrive(abs_path)
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      quoted_path = drive.upper() + urllib.quote((rest.replace('\\', '/')))
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 'file:///' + quoted_path
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      quoted_path = urllib.quote(abs_path)
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 'file://' + quoted_path
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetFileURLForDataPath(*relative_path):
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get file:// url for the given path relative to the chrome test data dir.
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Also quotes the url using urllib.quote().
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      relative_path: Variable number of strings that can be joined.
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PyUITest.GetFileURLForPath(PyUITest.DataDir(), *relative_path)
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetHttpURLForDataPath(*relative_path):
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get http:// url for the given path in the data dir.
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The URL will be usable only after starting the http server.
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global _HTTP_SERVER
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert _HTTP_SERVER, 'HTTP Server not yet started'
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return _HTTP_SERVER.GetURL(os.path.join('files', *relative_path)).spec()
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ContentDataDir():
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get path to content/test/data."""
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return os.path.join(PyUITest.DataDir(), os.pardir, os.pardir, os.pardir,
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'content', 'test', 'data')
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetFileURLForContentDataPath(*relative_path):
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get file:// url for the given path relative to content test data dir.
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Also quotes the url using urllib.quote().
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      relative_path: Variable number of strings that can be joined.
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PyUITest.GetFileURLForPath(PyUITest.ContentDataDir(), *relative_path)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetFtpURLForDataPath(ftp_server, *relative_path):
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get ftp:// url for the given path in the data dir.
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
640c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ftp_server: handle to ftp server, an instance of SpawnedTestServer
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      relative_path: any number of path elements
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The URL will be usable only after starting the ftp server.
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert ftp_server, 'FTP Server not yet started'
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ftp_server.GetURL(os.path.join(*relative_path)).spec()
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsMac():
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Are we on Mac?"""
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'darwin' == sys.platform
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsLinux():
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Are we on Linux? ChromeOS is linux too."""
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return sys.platform.startswith('linux')
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsWin():
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Are we on Win?"""
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'win32' == sys.platform
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsWin7():
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Are we on Windows 7?"""
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not PyUITest.IsWin():
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ver = sys.getwindowsversion()
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (ver[3], ver[0], ver[1]) == (2, 6, 1)
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsWinVista():
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Are we on Windows Vista?"""
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not PyUITest.IsWin():
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ver = sys.getwindowsversion()
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (ver[3], ver[0], ver[1]) == (2, 6, 0)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsWinXP():
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Are we on Windows XP?"""
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not PyUITest.IsWin():
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ver = sys.getwindowsversion()
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (ver[3], ver[0], ver[1]) == (2, 5, 1)
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsChromeOS():
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Are we on ChromeOS (or Chromium OS)?
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Checks for "CHROMEOS_RELEASE_NAME=" in /etc/lsb-release.
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    lsb_release = '/etc/lsb-release'
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not PyUITest.IsLinux() or not os.path.isfile(lsb_release):
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for line in open(lsb_release).readlines():
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if line.startswith('CHROMEOS_RELEASE_NAME='):
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return True
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return False
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsPosix():
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Are we on Mac/Linux?"""
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PyUITest.IsMac() or PyUITest.IsLinux()
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsEnUS():
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Are we en-US?"""
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO: figure out the machine's langugage.
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return True
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetPlatform():
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return the platform name."""
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Since ChromeOS is also Linux, we check for it first.
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if PyUITest.IsChromeOS():
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 'chromeos'
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif PyUITest.IsLinux():
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 'linux'
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif PyUITest.IsMac():
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 'mac'
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif PyUITest.IsWin():
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 'win'
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 'unknown'
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def EvalDataFrom(filename):
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return eval of python code from given file.
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The datastructure used in the file will be preserved.
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data_file = os.path.join(filename)
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents = open(data_file).read()
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = eval(contents)
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except:
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print >>sys.stderr, '%s is an invalid data file.' % data_file
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ChromeOSBoard():
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """What is the ChromeOS board name"""
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if PyUITest.IsChromeOS():
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for line in open('/etc/lsb-release'):
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        line = line.strip()
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if line.startswith('CHROMEOS_RELEASE_BOARD='):
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return line.split('=')[1]
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return None
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Kill(pid):
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Terminate the given pid.
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    If the pid refers to a renderer, use KillRendererProcess instead.
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if PyUITest.IsWin():
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      subprocess.call(['taskkill.exe', '/T', '/F', '/PID', str(pid)])
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.kill(pid, signal.SIGTERM)
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetPrivateInfo():
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Fetch info from private_tests_info.txt in private dir.
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a dictionary of items from private_tests_info.txt
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private_file = os.path.join(
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PyUITest.DataDir(), 'pyauto_private', 'private_tests_info.txt')
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert os.path.exists(private_file), '%s missing' % private_file
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PyUITest.EvalDataFrom(private_file)
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitUntil(self, function, timeout=-1, retry_sleep=0.25, args=[],
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                expect_retval=None, return_retval=False, debug=True):
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Poll on a condition until timeout.
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Waits until the |function| evalues to |expect_retval| or until |timeout|
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    secs, whichever occurs earlier.
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is better than using a sleep, since it waits (almost) only as much
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    as needed.
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WARNING: This method call should be avoided as far as possible in favor
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    of a real wait from chromium (like wait-until-page-loaded).
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Only use in case there's really no better option.
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXAMPLES:-
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Wait for "file.txt" to get created:
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WaitUntil(os.path.exists, args=["file.txt"])
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Same as above, but using lambda:
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WaitUntil(lambda: os.path.exists("file.txt"))
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      function: the function whose truth value is to be evaluated
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout: the max timeout (in secs) for which to wait. The default
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               action is to wait for kWaitForActionMaxMsec, as set in
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               ui_test.cc
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               Use None to wait indefinitely.
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      retry_sleep: the sleep interval (in secs) before retrying |function|.
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   Defaults to 0.25 secs.
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      args: the args to pass to |function|
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expect_retval: the expected return value for |function|. This forms the
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     exit criteria. In case this is None (the default),
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     |function|'s return value is checked for truth,
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     so 'non-empty-string' should match with True
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return_retval: If True, return the value returned by the last call to
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     |function()|
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      debug: if True, displays debug info at each retry.
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The return value of the |function| (when return_retval == True)
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True, if returning when |function| evaluated to True (when
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return_retval == False)
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      False, when returning due to timeout
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if timeout == -1:  # Default
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout = self._automation_timeout / 1000.0
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert callable(function), "function should be a callable"
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    begin = time.time()
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debug_begin = begin
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    retval = None
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while timeout is None or time.time() - begin <= timeout:
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      retval = function(*args)
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (expect_retval is None and retval) or \
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (expect_retval is not None and expect_retval == retval):
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return retval if return_retval else True
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if debug and time.time() - debug_begin > 5:
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        debug_begin += 5
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if function.func_name == (lambda: True).func_name:
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          function_info = inspect.getsource(function).strip()
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          function_info = '%s()' % function.func_name
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.debug('WaitUntil(%s:%d %s) still waiting. '
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      'Expecting %s. Last returned %s.',
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      os.path.basename(inspect.getsourcefile(function)),
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      inspect.getsourcelines(function)[1],
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      function_info,
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      True if expect_retval is None else expect_retval,
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      retval)
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      time.sleep(retry_sleep)
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return retval if return_retval else False
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def StartFTPServer(self, data_dir):
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Start a local file server hosting data files over ftp://
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data_dir: path where ftp files should be served
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
853c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      handle to FTP Server, an instance of SpawnedTestServer
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
855c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ftp_server = pyautolib.SpawnedTestServer(
856c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        pyautolib.SpawnedTestServer.TYPE_FTP,
857c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        '127.0.0.1',
858c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        pyautolib.FilePath(data_dir))
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert ftp_server.Start(), 'Could not start ftp server'
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug('Started ftp server at "%s".', data_dir)
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ftp_server
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def StopFTPServer(self, ftp_server):
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Stop the local ftp server."""
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert ftp_server, 'FTP Server not yet started'
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert ftp_server.Stop(), 'Could not stop ftp server'
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug('Stopped ftp server.')
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def StartHTTPServer(self, data_dir):
870c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    """Starts a local HTTP SpawnedTestServer serving files from |data_dir|.
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
873c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      data_dir: path where the SpawnedTestServer should serve files from.
874c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      This will be appended to the source dir to get the final document root.
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
877c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      handle to the HTTP SpawnedTestServer
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
879c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    http_server = pyautolib.SpawnedTestServer(
880c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        pyautolib.SpawnedTestServer.TYPE_HTTP,
881c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        '127.0.0.1',
882c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        pyautolib.FilePath(data_dir))
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert http_server.Start(), 'Could not start HTTP server'
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug('Started HTTP server at "%s".', data_dir)
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return http_server
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def StopHTTPServer(self, http_server):
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert http_server, 'HTTP server not yet started'
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert http_server.Stop(), 'Cloud not stop the HTTP server'
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug('Stopped HTTP server.')
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def StartHttpsServer(self, cert_type, data_dir):
893c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    """Starts a local HTTPS SpawnedTestServer serving files from |data_dir|.
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cert_type: An instance of SSLOptions.ServerCertificate for three
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 certificate types: ok, expired, or mismatch.
898c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      data_dir: The path where SpawnedTestServer should serve files from.
899c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                This is appended to the source dir to get the final
900c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                document root.
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
903c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      Handle to the HTTPS SpawnedTestServer
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
905c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    https_server = pyautolib.SpawnedTestServer(
906c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        pyautolib.SpawnedTestServer.TYPE_HTTPS,
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pyautolib.SSLOptions(cert_type),
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pyautolib.FilePath(data_dir))
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert https_server.Start(), 'Could not start HTTPS server.'
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug('Start HTTPS server at "%s".' % data_dir)
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return https_server
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def StopHttpsServer(self, https_server):
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert https_server, 'HTTPS server not yet started.'
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert https_server.Stop(), 'Could not stop the HTTPS server.'
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug('Stopped HTTPS server.')
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class ActionTimeoutChanger(object):
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Facilitate temporary changes to PyAuto command timeout.
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Automatically resets to original timeout when object is destroyed.
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _saved_timeout = -1  # Saved timeout value
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def __init__(self, ui_test, new_timeout):
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """Initialize.
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Args:
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ui_test: a PyUITest object
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_timeout: new timeout to use (in milli secs)
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._saved_timeout = ui_test._automation_timeout
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui_test._automation_timeout = new_timeout
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._ui_test = ui_test
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def __del__(self):
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """Reset command_execution_timeout_ms to original value."""
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._ui_test._automation_timeout = self._saved_timeout
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class JavascriptExecutor(object):
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Abstract base class for JavaScript injection.
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Derived classes should override Execute method."""
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def Execute(self, script):
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pass
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class JavascriptExecutorInTab(JavascriptExecutor):
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Wrapper for injecting JavaScript in a tab."""
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def __init__(self, ui_test, tab_index=0, windex=0, frame_xpath=''):
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """Initialize.
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Refer to ExecuteJavascript() for the complete argument list
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        description.
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Args:
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ui_test: a PyUITest object
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._ui_test = ui_test
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.windex = windex
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.tab_index = tab_index
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.frame_xpath = frame_xpath
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def Execute(self, script):
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """Execute script in the tab."""
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return self._ui_test.ExecuteJavascript(script,
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             self.tab_index,
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             self.windex,
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             self.frame_xpath)
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class JavascriptExecutorInRenderView(JavascriptExecutor):
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Wrapper for injecting JavaScript in an extension view."""
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def __init__(self, ui_test, view, frame_xpath=''):
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """Initialize.
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Refer to ExecuteJavascriptInRenderView() for the complete argument list
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        description.
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Args:
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ui_test: a PyUITest object
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._ui_test = ui_test
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.view = view
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.frame_xpath = frame_xpath
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def Execute(self, script):
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """Execute script in the render view."""
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return self._ui_test.ExecuteJavascriptInRenderView(script,
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                         self.view,
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                         self.frame_xpath)
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetResultFromJSONRequestDiagnostics(self):
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Same as _GetResultFromJSONRequest without throwing a timeout exception.
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This method is used to diagnose if a command returns without causing a
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timout exception to be thrown.  This should be used for debugging purposes
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    only.
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True if the request returned; False if it timed out.
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._SendJSONRequest(-1,
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             json.dumps({'command': 'GetBrowserInfo',}),
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             self._automation_timeout)
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not result:
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # The diagnostic command did not complete, Chrome is probably in a bad
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # state
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return True
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetResultFromJSONRequest(self, cmd_dict, windex=0, timeout=-1):
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Issue call over the JSON automation channel and fetch output.
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This method packages the given dictionary into a json string, sends it
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    over the JSON automation channel, loads the json output string returned,
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    and returns it back as a dictionary.
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd_dict: the command dictionary. It must have a 'command' key
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                Sample:
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  {
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    'command': 'SetOmniboxText',
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    'text': text,
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  }
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: 0-based window index on which to work. Default: 0 (first window)
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              Use -ve windex or None if the automation command does not apply
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              to a browser window. Example: for chromeos login
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout: request timeout (in milliseconds)
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a dictionary for the output returned by the automation channel.
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if timeout == -1:  # Default
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout = self._automation_timeout
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if windex is None:  # Do not target any window
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex = -1
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._SendJSONRequest(windex, json.dumps(cmd_dict), timeout)
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not result:
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      additional_info = 'No information available.'
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Windows does not support os.kill until Python 2.7.
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not self.IsWin() and _BROWSER_PID:
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        browser_pid_exists = True
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Does the browser PID exist?
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try:
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          # Does not actually kill the process
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          os.kill(int(_BROWSER_PID), 0)
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        except OSError:
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          browser_pid_exists = False
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if browser_pid_exists:
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if self._GetResultFromJSONRequestDiagnostics():
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # Browser info, worked, that means this hook had a problem
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            additional_info = ('The browser process ID %d still exists. '
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               'PyAuto was able to obtain browser info. It '
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               'is possible this hook is broken.'
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               % _BROWSER_PID)
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          else:
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            additional_info = ('The browser process ID %d still exists. '
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               'PyAuto was not able to obtain browser info. '
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               'It is possible the browser is hung.'
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               % _BROWSER_PID)
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          additional_info = ('The browser process ID %d no longer exists. '
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             'Perhaps the browser crashed.' % _BROWSER_PID)
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif not _BROWSER_PID:
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        additional_info = ('The browser PID was not obtained. Does this test '
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           'have a unique startup configuration?')
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Mask private data if it is in the JSON dictionary
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd_dict_copy = copy.copy(cmd_dict)
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'password' in cmd_dict_copy.keys():
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cmd_dict_copy['password'] = '**********'
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'username' in cmd_dict_copy.keys():
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cmd_dict_copy['username'] = 'removed_username'
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise JSONInterfaceError('Automation call %s received empty response.  '
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               'Additional information:\n%s' % (cmd_dict_copy,
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               additional_info))
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret_dict = json.loads(result)
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ret_dict.has_key('error'):
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if ret_dict.get('is_interface_timeout'):
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise AutomationCommandTimeout(ret_dict['error'])
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif ret_dict.get('is_interface_error'):
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise JSONInterfaceError(ret_dict['error'])
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise AutomationCommandFail(ret_dict['error'])
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret_dict
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def NavigateToURL(self, url, windex=0, tab_index=None, navigation_count=1):
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Navigate the given tab to the given URL.
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Note that this method also activates the corresponding tab/window if it's
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    not active already. Blocks until |navigation_count| navigations have
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    completed.
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url: The URL to which to navigate, can be a string or GURL object.
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to the first
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: The index of the tab to work on. Defaults to the active tab.
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      navigation_count: the number of navigations to wait for. Defaults to 1.
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(url, GURL):
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url = url.spec()
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if tab_index is None:
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index = self.GetActiveTabIndex(windex)
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'NavigateToURL',
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'url': url,
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'tab_index': tab_index,
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'navigation_count': navigation_count,
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def NavigateToURLAsync(self, url, windex=0, tab_index=None):
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Initiate a URL navigation.
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    A wrapper for NavigateToURL with navigation_count set to 0.
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.NavigateToURL(url, windex, tab_index, 0)
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ApplyAccelerator(self, accelerator, windex=0):
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Apply the accelerator with the given id.
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Note that this method schedules the accelerator, but does not wait for it to
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    actually finish doing anything.
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      accelerator: The accelerator id, IDC_BACK, IDC_NEWTAB, etc. The list of
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ids can be found at chrome/app/chrome_command_ids.h.
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to the first
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'ApplyAccelerator',
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'accelerator': accelerator,
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RunCommand(self, accelerator, windex=0):
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Apply the accelerator with the given id and wait for it to finish.
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is like ApplyAccelerator except that it waits for the command to finish
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    executing.
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      accelerator: The accelerator id. The list of ids can be found at
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          chrome/app/chrome_command_ids.h.
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to the first
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'RunCommand',
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'accelerator': accelerator,
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsMenuCommandEnabled(self, accelerator, windex=0):
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Check if a command is enabled for a window.
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns true if the command with the given accelerator id is enabled on the
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    given window.
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      accelerator: The accelerator id. The list of ids can be found at
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          chrome/app/chrome_command_ids.h.
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to the first
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True if the command is enabled for the given window.
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'IsMenuCommandEnabled',
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'accelerator': accelerator,
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None).get('enabled')
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def TabGoForward(self, tab_index=0, windex=0):
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Navigate a tab forward in history.
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Equivalent to clicking the Forward button in the UI. Activates the tab as a
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    side effect.
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.ActivateTab(tab_index, windex)
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.RunCommand(IDC_FORWARD, windex)
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def TabGoBack(self, tab_index=0, windex=0):
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Navigate a tab backwards in history.
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Equivalent to clicking the Back button in the UI. Activates the tab as a
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    side effect.
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.ActivateTab(tab_index, windex)
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.RunCommand(IDC_BACK, windex)
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ReloadTab(self, tab_index=0, windex=0):
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Reload the given tab.
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Blocks until the page has reloaded.
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: The index of the tab to reload. Defaults to 0.
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to the first
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.ActivateTab(tab_index, windex)
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.RunCommand(IDC_RELOAD, windex)
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CloseTab(self, tab_index=0, windex=0, wait_until_closed=True):
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Close the given tab.
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Note: Be careful closing the last tab in a window as it may close the
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        browser.
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: The index of the tab to reload. Defaults to 0.
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to the first
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wait_until_closed: Whether to block until the tab finishes closing.
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'CloseTab',
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'tab_index': tab_index,
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'wait_until_closed': wait_until_closed,
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitForTabToBeRestored(self, tab_index=0, windex=0, timeout=-1):
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Wait for the given tab to be restored.
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: The index of the tab to reload. Defaults to 0.
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to the first
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout: Timeout in milliseconds.
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'CloseTab',
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'tab_index': tab_index,
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None, timeout=timeout)
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ReloadActiveTab(self, windex=0):
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Reload an active tab.
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Warning: Depending on the concept of an active tab is dangerous as it can
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    change during the test. Use ReloadTab and supply a tab_index explicitly.
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to the first
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.ReloadTab(self.GetActiveTabIndex(windex), windex)
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetActiveTabIndex(self, windex=0):
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get the index of the currently active tab in the given browser window.
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Warning: Depending on the concept of an active tab is dangerous as it can
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    change during the test. Supply the tab_index explicitly, if possible.
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to the first
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      An integer index for the currently active tab.
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'GetActiveTabIndex',
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict,
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          windex=None).get('tab_index')
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ActivateTab(self, tab_index=0, windex=0):
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Activates the given tab in the specified window.
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Warning: Depending on the concept of an active tab is dangerous as it can
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    change during the test. Instead use functions that accept a tab_index
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    explicitly.
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: Integer index of the tab to activate; defaults to 0.
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'ActivateTab',
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'tab_index': tab_index,
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.BringBrowserToFront(windex)
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def BringBrowserToFront(self, windex=0):
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Activate the browser's window and bring it to front.
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'BringBrowserToFront',
13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetBrowserWindowCount(self):
13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get the browser window count.
13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None.
13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Integer count of the number of browser windows. Includes popups.
13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {'command': 'GetBrowserWindowCount'}
13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)['count']
13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def OpenNewBrowserWindow(self, show):
13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Create a new browser window.
13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      show: Boolean indicating whether to show the window.
13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'OpenNewBrowserWindow',
13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'show': show,
13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CloseBrowserWindow(self, windex=0):
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Create a new browser window.
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Index of the browser window to close; defaults to 0.
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'CloseBrowserWindow',
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AppendTab(self, url, windex=0):
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Append a new tab.
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Creates a new tab at the end of given browser window and activates
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    it. Blocks until the specified |url| is loaded.
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url: The url to load, can be string or a GURL object.
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to the first
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True if the url loads successfully in the new tab. False otherwise.
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(url, GURL):
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url = url.spec()
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'AppendTab',
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'url': url,
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None).get('result')
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetTabCount(self, windex=0):
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the number of tab in the given browser window.
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The tab count.
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'GetTabCount',
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)['tab_count']
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetTabInfo(self, tab_index=0, windex=0):
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets information about the specified tab.
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: Integer index of the tab to activate; defaults to 0.
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary containing information about the tab.
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Example:
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        { u'title': "Hello World",
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'url': "http://foo.bar", }
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'GetTabInfo',
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'tab_index': tab_index,
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetActiveTabTitle(self, windex=0):
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the title of the active tab.
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Warning: Depending on the concept of an active tab is dangerous as it can
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    change during the test. Use GetTabInfo and supply a tab_index explicitly.
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The tab title as a string.
14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.GetTabInfo(self.GetActiveTabIndex(windex), windex)['title']
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetActiveTabURL(self, windex=0):
14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the URL of the active tab.
14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Warning: Depending on the concept of an active tab is dangerous as it can
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    change during the test. Use GetTabInfo and supply a tab_index explicitly.
14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The tab URL as a GURL object.
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GURL(str(self.GetTabInfo(self.GetActiveTabIndex(windex),
14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    windex)['url']))
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ActionOnSSLBlockingPage(self, tab_index=0, windex=0, proceed=True):
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Take action on an interstitial page.
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Calling this when an interstitial page is not showing is an error.
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: Integer index of the tab to activate; defaults to 0.
15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proceed: Whether to proceed to the URL or not.
15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'ActionOnSSLBlockingPage',
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'tab_index': tab_index,
15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'proceed': proceed,
15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetBookmarkModel(self, windex=0):
15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return the bookmark model as a BookmarkModel object.
15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is a snapshot of the bookmark model; it is not a proxy and
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    does not get updated as the bookmark model changes.
15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bookmarks_as_json = self._GetBookmarksAsJSON(windex)
15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not bookmarks_as_json:
15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise JSONInterfaceError('Could not resolve browser proxy.')
15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return bookmark_model.BookmarkModel(bookmarks_as_json)
15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetBookmarksAsJSON(self, windex=0):
15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get bookmarks as a JSON dictionary; used by GetBookmarkModel()."""
15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
15365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'GetBookmarksAsJSON',
15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WaitForBookmarkModelToLoad(windex)
15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict,
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          windex=None)['bookmarks_as_json']
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitForBookmarkModelToLoad(self, windex=0):
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the status of the bookmark bar as a dictionary.
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
15475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
15485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
15495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'WaitForBookmarkModelToLoad',
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetBookmarkBarStatus(self, windex=0):
15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the status of the bookmark bar as a dictionary.
15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary.
15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Example:
15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        { u'visible': True,
15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'animating': False,
15715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'detached': False, }
15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
15755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
15775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'GetBookmarkBarStatus',
15785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
15795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetBookmarkBarStatus(self, windex=0):
15835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the status of the bookmark bar as a dictionary.
15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
15875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary.
15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Example:
15925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        { u'visible': True,
15935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'animating': False,
15945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'detached': False, }
15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
15985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'GetBookmarkBarStatus',
16015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetBookmarkBarStatus(self, windex=0):
16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the status of the bookmark bar as a dictionary.
16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
16105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
16115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary.
16145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Example:
16155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        { u'visible': True,
16165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'animating': False,
16175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'detached': False, }
16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'GetBookmarkBarStatus',
16245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
16255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetBookmarkBarVisibility(self, windex=0):
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the visibility of the bookmark bar.
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
16335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
16365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True if the bookmark bar is visible, false otherwise.
16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
16395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
16415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.GetBookmarkBarStatus(windex)['visible']
16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AddBookmarkGroup(self, parent_id, index, title, windex=0):
16445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Adds a bookmark folder.
16455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_id: The parent bookmark folder.
16485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index: The location in the parent's list to insert this bookmark folder.
16495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      title: The name of the bookmark folder.
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
16515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
16545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True if the bookmark bar is detached, false otherwise.
16555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
16575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(parent_id, basestring):
16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_id = int(parent_id)
16615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
16625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'AddBookmark',
16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'parent_id': parent_id,
16645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'index': index,
16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'title': title,
16665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'is_folder': True,
16675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
16685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WaitForBookmarkModelToLoad(windex)
16705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
16715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AddBookmarkURL(self, parent_id, index, title, url, windex=0):
16735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Add a bookmark URL.
16745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
16765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_id: The parent bookmark folder.
16775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index: The location in the parent's list to insert this bookmark.
16785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      title: The name of the bookmark.
16795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url: The url of the bookmark.
16805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
16815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
16825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
16845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
16855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
16865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(parent_id, basestring):
16875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_id = int(parent_id)
16885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
16895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'AddBookmark',
16905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'parent_id': parent_id,
16915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'index': index,
16925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'title': title,
16935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'url': url,
16945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'is_folder': False,
16955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
16965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WaitForBookmarkModelToLoad(windex)
16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ReparentBookmark(self, id, new_parent_id, index, windex=0):
17015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Move a bookmark.
17025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
17045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id: The bookmark to move.
17055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_parent_id: The new parent bookmark folder.
17065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index: The location in the parent's list to insert this bookmark.
17075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
17085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
17095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
17115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
17125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
17135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(id, basestring):
17145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id = int(id)
17155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(new_parent_id, basestring):
17165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_parent_id = int(new_parent_id)
17175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
17185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'ReparentBookmark',
17195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'id': id,
17205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'new_parent_id': new_parent_id,
17215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'index': index,
17225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
17235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
17245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WaitForBookmarkModelToLoad(windex)
17255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetBookmarkTitle(self, id, title, windex=0):
17285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Change the title of a bookmark.
17295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
17315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id: The bookmark to rename.
17325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      title: The new title for the bookmark.
17335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
17345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
17355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
17375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
17385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(id, basestring):
17405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id = int(id)
17415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
17425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'SetBookmarkTitle',
17435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'id': id,
17445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'title': title,
17455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
17465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
17475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WaitForBookmarkModelToLoad(windex)
17485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
17495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetBookmarkURL(self, id, url, windex=0):
17515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Change the URL of a bookmark.
17525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
17545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id: The bookmark to change.
17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url: The new url for the bookmark.
17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
17615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
17625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(id, basestring):
17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id = int(id)
17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'SetBookmarkURL',
17665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'id': id,
17675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'url': url,
17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
17695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
17705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WaitForBookmarkModelToLoad(windex)
17715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
17725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RemoveBookmark(self, id, windex=0):
17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Remove a bookmark.
17755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id: The bookmark to remove.
17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to the first
17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
17805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(id, basestring):
17855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id = int(id)
17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'RemoveBookmark',
17885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'id': id,
17895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
17905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
17915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WaitForBookmarkModelToLoad(windex)
17925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
17935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetDownloadsInfo(self, windex=0):
17955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return info about downloads.
17965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This includes all the downloads recognized by the history system.
17985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      an instance of downloads_info.DownloadInfo
18015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
18025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return download_info.DownloadInfo(
18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._GetResultFromJSONRequest({'command': 'GetDownloadsInfo'},
18045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       windex=windex))
18055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetOmniboxInfo(self, windex=0):
18075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return info about Omnibox.
18085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This represents a snapshot of the omnibox.  If you expect changes
18105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    you need to call this method again to get a fresh snapshot.
18115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Note that this DOES NOT shift focus to the omnibox; you've to ensure that
18125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the omnibox is in focus or else you won't get any interesting info.
18135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    It's OK to call this even when the omnibox popup is not showing.  In this
18155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case however, there won't be any matches, but other properties (like the
18165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    current text in the omnibox) will still be fetched.
18175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Due to the nature of the omnibox, this function is sensitive to mouse
18195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    focus.  DO NOT HOVER MOUSE OVER OMNIBOX OR CHANGE WINDOW FOCUS WHEN USING
18205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    THIS METHOD.
18215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
18235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: the index of the browser window to work on.
18245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              Default: 0 (first window)
18255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
18275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      an instance of omnibox_info.OmniboxInfo
18285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
18295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return omnibox_info.OmniboxInfo(
18305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._GetResultFromJSONRequest({'command': 'GetOmniboxInfo'},
18315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       windex=windex))
18325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetOmniboxText(self, text, windex=0):
18345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Enter text into the omnibox. This shifts focus to the omnibox.
18355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      text: the text to be set.
18385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: the index of the browser window to work on.
18395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              Default: 0 (first window)
18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
18415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Ensure that keyword data is loaded from the profile.
18425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # This would normally be triggered by the user inputting this text.
18435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest({'command': 'LoadSearchEngineInfo'})
18445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
18455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'SetOmniboxText',
18465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'text': text,
18475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
18485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=windex)
18495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # TODO(ace): Remove this hack, update bug 62783.
18515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitUntilOmniboxReadyHack(self, windex=0):
18525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Wait until the omnibox is ready for input.
18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is a hack workaround for linux platform, which returns from
18555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    synchronous window creation methods before the omnibox is fully functional.
18565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    No-op on non-linux platforms.
18585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: the index of the browser to work on.
18615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
18625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.IsLinux():
18635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return self.WaitUntil(
18645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          lambda : self.GetOmniboxInfo(windex).Properties('has_focus'))
18655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitUntilOmniboxQueryDone(self, windex=0):
18675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Wait until omnibox has finished populating results.
18685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Uses WaitUntil() so the wait duration is capped by the timeout values
18705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    used by automation, which WaitUntil() uses.
18715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
18735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: the index of the browser window to work on.
18745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              Default: 0 (first window)
18755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
18765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.WaitUntil(
18775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        lambda : not self.GetOmniboxInfo(windex).IsQueryInProgress())
18785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def OmniboxMovePopupSelection(self, count, windex=0):
18805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Move omnibox popup selection up or down.
18815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
18835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      count: number of rows by which to move.
18845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             -ve implies down, +ve implies up
18855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: the index of the browser window to work on.
18865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              Default: 0 (first window)
18875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
18885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
18895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'OmniboxMovePopupSelection',
18905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'count': count,
18915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
18925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=windex)
18935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def OmniboxAcceptInput(self, windex=0):
18955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Accepts the current string of text in the omnibox.
18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is equivalent to clicking or hiting enter on a popup selection.
18985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Blocks until the page loads.
18995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
19015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: the index of the browser window to work on.
19025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              Default: 0 (first window)
19035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
19045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
19055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'OmniboxAcceptInput',
19065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=windex)
19085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetCookie(self, url, windex=0):
19105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get the value of the cookie at url in context of the specified browser.
19115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
19135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url: Either a GURL object or url string specifing the cookie url.
19145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to the first
19155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
19165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
19185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
19195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
19205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(url, GURL):
19215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url = url.spec()
19225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
19235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'GetCookiesInBrowserContext',
19245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'url': url,
19255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
19265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)['cookies']
19285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def DeleteCookie(self, url, cookie_name, windex=0):
19305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Delete the cookie at url with name cookie_name.
19315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url: Either a GURL object or url string specifing the cookie url.
19345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cookie_name: The name of the cookie to delete as a string.
19355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to the first
19365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
19375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
19395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
19405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
19415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(url, GURL):
19425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url = url.spec()
19435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
19445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'DeleteCookieInBrowserContext',
19455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'url': url,
19465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'cookie_name': cookie_name,
19475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
19485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
19505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetCookie(self, url, value, windex=0):
19525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Set the value of the cookie at url to value in the context of a browser.
19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
19555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url: Either a GURL object or url string specifing the cookie url.
19565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value: A string to set as the cookie's value.
19575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to the first
19585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.
19595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
19615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(url, GURL):
19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url = url.spec()
19655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
19665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'SetCookieInBrowserContext',
19675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'url': url,
19685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'value': value,
19695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
19705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetSearchEngineInfo(self, windex=0):
19745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return info about search engines.
19755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
19775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The window index, default is 0.
19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
19805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      An ordered list of dictionaries describing info about each search engine.
19815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Example:
19835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        [ { u'display_url': u'{google:baseURL}search?q=%s',
19845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'host': u'www.google.com',
19855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'in_default_list': True,
19865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'is_default': True,
19875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'is_valid': True,
19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'keyword': u'google.com',
19895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'path': u'/search',
19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'short_name': u'Google',
19915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'supports_replacement': True,
19925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'url': u'{google:baseURL}search?q={searchTerms}'},
19935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          { u'display_url': u'http://search.yahoo.com/search?p=%s',
19945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'host': u'search.yahoo.com',
19955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'in_default_list': True,
19965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'is_default': False,
19975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'is_valid': True,
19985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'keyword': u'yahoo.com',
19995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'path': u'/search',
20005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'short_name': u'Yahoo!',
20015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'supports_replacement': True,
20025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'url': u'http://search.yahoo.com/search?p={searchTerms}'},
20035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Ensure that the search engine profile is loaded into data model.
20055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest({'command': 'LoadSearchEngineInfo'},
20065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   windex=windex)
20075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {'command': 'GetSearchEngineInfo'}
20085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(
20095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cmd_dict, windex=windex)['search_engines']
20105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AddSearchEngine(self, title, keyword, url, windex=0):
20125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Add a search engine, as done through the search engines UI.
20135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
20155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      title: name for search engine.
20165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      keyword: keyword, used to initiate a custom search from omnibox.
20175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url: url template for this search engine's query.
20185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           '%s' is replaced by search query string when used to search.
20195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The window index, default is 0.
20205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
20215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Ensure that the search engine profile is loaded into data model.
20225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest({'command': 'LoadSearchEngineInfo'},
20235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   windex=windex)
20245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {'command': 'AddOrEditSearchEngine',
20255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'new_title': title,
20265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'new_keyword': keyword,
20275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'new_url': url}
20285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=windex)
20295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def EditSearchEngine(self, keyword, new_title, new_keyword, new_url,
20315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       windex=0):
20325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Edit info for existing search engine.
20335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
20355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      keyword: existing search engine keyword.
20365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_title: new name for this search engine.
20375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_keyword: new keyword for this search engine.
20385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_url: new url for this search engine.
20395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The window index, default is 0.
20405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
20415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Ensure that the search engine profile is loaded into data model.
20425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest({'command': 'LoadSearchEngineInfo'},
20435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   windex=windex)
20445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {'command': 'AddOrEditSearchEngine',
20455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'keyword': keyword,
20465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'new_title': new_title,
20475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'new_keyword': new_keyword,
20485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'new_url': new_url}
20495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=windex)
20505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def DeleteSearchEngine(self, keyword, windex=0):
20525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Delete search engine with given keyword.
20535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
20555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      keyword: the keyword string of the search engine to delete.
20565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The window index, default is 0.
20575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
20585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Ensure that the search engine profile is loaded into data model.
20595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest({'command': 'LoadSearchEngineInfo'},
20605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   windex=windex)
20615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {'command': 'PerformActionOnSearchEngine', 'keyword': keyword,
20625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'action': 'delete'}
20635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=windex)
20645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def MakeSearchEngineDefault(self, keyword, windex=0):
20665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Make search engine with given keyword the default search.
20675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
20695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      keyword: the keyword string of the search engine to make default.
20705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The window index, default is 0.
20715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
20725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Ensure that the search engine profile is loaded into data model.
20735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest({'command': 'LoadSearchEngineInfo'},
20745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   windex=windex)
20755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {'command': 'PerformActionOnSearchEngine', 'keyword': keyword,
20765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'action': 'default'}
20775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=windex)
20785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetLocalStatePrefsInfo(self):
20805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return info about preferences.
20815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This represents a snapshot of the local state preferences. If you expect
20835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    local state preferences to have changed, you need to call this method again
20845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    to get a fresh snapshot.
20855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
20875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      an instance of prefs_info.PrefsInfo
20885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
20895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return prefs_info.PrefsInfo(
20905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._GetResultFromJSONRequest({'command': 'GetLocalStatePrefsInfo'},
20915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       windex=None))
20925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetLocalStatePrefs(self, path, value):
20945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Set local state preference for the given path.
20955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Preferences are stored by Chromium as a hierarchical dictionary.
20975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dot-separated paths can be used to refer to a particular preference.
20985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    example: "session.restore_on_startup"
20995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Some preferences are managed, that is, they cannot be changed by the
21015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    user. It's up to the user to know which ones can be changed. Typically,
21025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the options available via Chromium preferences can be changed.
21035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
21055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path: the path the preference key that needs to be changed
21065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            example: "session.restore_on_startup"
21075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            One of the equivalent names in chrome/common/pref_names.h could
21085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            also be used.
21095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value: the value to be set. It could be plain values like int, bool,
21105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             string or complex ones like list.
21115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             The user has to ensure that the right value is specified for the
21125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             right key. It's useful to dump the preferences first to determine
21135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             what type is expected for a particular preference path.
21145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
21155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
21165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'SetLocalStatePrefs',
21175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': 0,
21185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'path': path,
21195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'value': value,
21205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
21225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetPrefsInfo(self, windex=0):
21245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return info about preferences.
21255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This represents a snapshot of the preferences. If you expect preferences
21275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    to have changed, you need to call this method again to get a fresh
21285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    snapshot.
21295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
21315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The window index, default is 0.
21325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
21335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      an instance of prefs_info.PrefsInfo
21345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
21355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
21365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetPrefsInfo',
21375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
21385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return prefs_info.PrefsInfo(
21405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._GetResultFromJSONRequest(cmd_dict, windex=None))
21415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetPrefs(self, path, value, windex=0):
21435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Set preference for the given path.
21445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Preferences are stored by Chromium as a hierarchical dictionary.
21465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dot-separated paths can be used to refer to a particular preference.
21475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    example: "session.restore_on_startup"
21485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Some preferences are managed, that is, they cannot be changed by the
21505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    user. It's up to the user to know which ones can be changed. Typically,
21515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the options available via Chromium preferences can be changed.
21525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
21545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path: the path the preference key that needs to be changed
21555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            example: "session.restore_on_startup"
21565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            One of the equivalent names in chrome/common/pref_names.h could
21575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            also be used.
21585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value: the value to be set. It could be plain values like int, bool,
21595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             string or complex ones like list.
21605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             The user has to ensure that the right value is specified for the
21615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             right key. It's useful to dump the preferences first to determine
21625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             what type is expected for a particular preference path.
21635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: window index to work on. Defaults to 0 (first window).
21645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
21655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
21665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'SetPrefs',
21675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
21685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'path': path,
21695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'value': value,
21705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
21725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SendWebkitKeyEvent(self, key_type, key_code, tab_index=0, windex=0):
21745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Send a webkit key event to the browser.
21755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
21775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key_type: the raw key type such as 0 for up and 3 for down.
21785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key_code: the hex value associated with the keypress (virtual key code).
21795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: tab index to work on. Defaults to 0 (first tab).
21805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: window index to work on. Defaults to 0 (first window).
21815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
21825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
21835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'SendWebkitKeyEvent',
21845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'type': key_type,
21855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'text': '',
21865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'isSystemKey': False,
21875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'unmodifiedText': '',
21885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'nativeKeyCode': 0,
21895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windowsKeyCode': key_code,
21905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'modifiers': 0,
21915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
21925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index': tab_index,
21935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
21945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Sending request for key event.
21955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
21965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SendWebkitCharEvent(self, char, tab_index=0, windex=0):
21985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Send a webkit char to the browser.
21995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
22015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      char: the char value to be sent to the browser.
22025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: tab index to work on. Defaults to 0 (first tab).
22035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: window index to work on. Defaults to 0 (first window).
22045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
22055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
22065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'SendWebkitKeyEvent',
22075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'type': 2,  # kCharType
22085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'text': char,
22095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'isSystemKey': False,
22105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'unmodifiedText': char,
22115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'nativeKeyCode': 0,
22125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windowsKeyCode': ord((char).upper()),
22135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'modifiers': 0,
22145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
22155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index': tab_index,
22165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Sending request for a char.
22185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
22195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetDownloadShelfVisible(self, is_visible, windex=0):
22215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Set download shelf visibility for the specified browser window.
22225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
22245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_visible: A boolean indicating the desired shelf visibility.
22255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The window index, defaults to 0 (the first window).
22265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
22285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
22295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
22305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
22315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'SetDownloadShelfVisible',
22325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'is_visible': is_visible,
22335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
22345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
22365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsDownloadShelfVisible(self, windex=0):
22385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Determine whether the download shelf is visible in the given window.
22395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
22415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The window index, defaults to 0 (the first window).
22425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A boolean indicating the shelf visibility.
22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
22475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
22485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
22495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
22505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'IsDownloadShelfVisible',
22515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
22525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)['is_visible']
22545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetDownloadDirectory(self, tab_index=None, windex=0):
22565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get the path to the download directory.
22575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Warning: Depending on the concept of an active tab is dangerous as it can
22595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    change during the test. Always supply a tab_index explicitly.
22605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
22625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: The index of the tab to work on. Defaults to the active tab.
22635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on. Defaults to 0.
22645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
22665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The path to the download directory as a FilePath object.
22675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
22695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
22705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
22715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if tab_index is None:
22725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index = self.GetActiveTabIndex(windex)
22735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
22745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetDownloadDirectory',
22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index': tab_index,
22765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
22775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FilePath(str(self._GetResultFromJSONRequest(cmd_dict,
22795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       windex=None)['path']))
22805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitForAllDownloadsToComplete(self, pre_download_ids=[], windex=0,
22825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    timeout=-1):
22835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Wait for all pending downloads to complete.
22845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This function assumes that any downloads to wait for have already been
22865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    triggered and have started (it is ok if those downloads complete before this
22875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function is called).
22885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
22905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pre_download_ids: A list of numbers representing the IDs of downloads that
22915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        exist *before* downloads to wait for have been
22925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        triggered. Defaults to []; use GetDownloadsInfo() to get
22935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        these IDs (only necessary if a test previously
22945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        downloaded files).
22955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The window index, defaults to 0 (the first window).
22965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout: The maximum amount of time (in milliseconds) to wait for
22975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               downloads to complete.
22985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
22995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
23005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'WaitForAllDownloadsToComplete',
23015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'pre_download_ids': pre_download_ids,
23025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
23035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=windex, timeout=timeout)
23045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def PerformActionOnDownload(self, id, action, window_index=0):
23065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Perform the given action on the download with the given id.
23075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
23095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id: The id of the download.
23105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      action: The action to perform on the download.
23115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              Possible actions:
23125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'open': Opens the download (waits until it has completed first).
23135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'toggle_open_files_like_this': Toggles the 'Always Open Files
23145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    Of This Type' option.
23155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'remove': Removes the file from downloads (not from disk).
23165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'decline_dangerous_download': Equivalent to 'Discard' option
23175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    after downloading a dangerous download (ex. an executable).
23185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'save_dangerous_download': Equivalent to 'Save' option after
23195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    downloading a dangerous file.
23202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                'pause': Pause the download.  If the download completed before
23212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    this call or is already paused, it's a no-op.
23222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                'resume': Resume the download.  If the download completed before
23232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    this call or was not paused, it's a no-op.
23245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'cancel': Cancel the download.
23255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window_index: The window index, default is 0.
23265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
23285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary representing the updated download item (except in the case
23295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      of 'decline_dangerous_download', 'toggle_open_files_like_this', and
23305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'remove', which return an empty dict).
23315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Example dictionary:
23325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { u'PercentComplete': 100,
23335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'file_name': u'file.txt',
23345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'full_path': u'/path/to/file.txt',
23355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'id': 0,
23365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'is_otr': False,
23375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'is_paused': False,
23385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'is_temporary': False,
23395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'open_when_complete': False,
23405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'referrer_url': u'',
23415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'state': u'COMPLETE',
23422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        u'danger_type': u'DANGEROUS_FILE',
23435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'url':  u'file://url/to/file.txt'
23445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
23455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
23465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
23475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'PerformActionOnDownload',
23485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'id': id,
23495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'action': action
23505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
23515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=window_index)
23525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def DownloadAndWaitForStart(self, file_url, windex=0):
23545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Trigger download for the given url and wait for downloads to start.
23555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    It waits for download by looking at the download info from Chrome, so
23575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    anything which isn't registered by the history service won't be noticed.
23585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is not thread-safe, but it's fine to call this method to start
23595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    downloading multiple files in parallel. That is after starting a
23605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    download, it's fine to start another one even if the first one hasn't
23615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    completed.
23625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
23635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
23645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      num_downloads = len(self.GetDownloadsInfo(windex).Downloads())
23655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except JSONInterfaceError:
23665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      num_downloads = 0
23675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.NavigateToURL(file_url, windex)  # Trigger download.
23695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # It might take a while for the download to kick in, hold on until then.
23705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertTrue(self.WaitUntil(
23715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        lambda: len(self.GetDownloadsInfo(windex).Downloads()) >
23725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                num_downloads))
23735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetWindowDimensions(
23755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self, x=None, y=None, width=None, height=None, windex=0):
23765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Set window dimensions.
23775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    All args are optional and current values will be preserved.
23795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Arbitrarily large values will be handled gracefully by the browser.
23805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
23825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      x: window origin x
23835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      y: window origin y
23845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      width: window width
23855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      height: window height
23865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: window index to work on. Defaults to 0 (first window)
23875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
23885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
23895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'SetWindowDimensions',
23905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
23915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if x:
23925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd_dict['x'] = x
23935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if y:
23945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd_dict['y'] = y
23955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if width:
23965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd_dict['width'] = width
23975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if height:
23985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd_dict['height'] = height
23995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=windex)
24005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitForInfobarCount(self, count, windex=0, tab_index=0):
24025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Wait until infobar count becomes |count|.
24035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Note: Wait duration is capped by the automation timeout.
24055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
24075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      count: requested number of infobars
24085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: window index.  Defaults to 0 (first window)
24095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: tab index  Defaults to 0 (first tab)
24105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
24125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
24135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
24145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(phajdan.jr): We need a solid automation infrastructure to handle
24155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # these cases. See crbug.com/53647.
24165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _InfobarCount():
24175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windows = self.GetBrowserInfo()['windows']
24185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if windex >= len(windows):  # not enough windows
24195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return -1
24205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tabs = windows[windex]['tabs']
24215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if tab_index >= len(tabs):  # not enough tabs
24225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return -1
24235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return len(tabs[tab_index]['infobars'])
24245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.WaitUntil(_InfobarCount, expect_retval=count)
24265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def PerformActionOnInfobar(
24285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self, action, infobar_index, windex=0, tab_index=0):
24295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Perform actions on an infobar.
24305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
24325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      action: the action to be performed.
24335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              Actions depend on the type of the infobar.  The user needs to
24345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              call the right action for the right infobar.
24355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              Valid inputs are:
24365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              - "dismiss": closes the infobar (for all infobars)
24375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              - "accept", "cancel": click accept / cancel (for confirm infobars)
24385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              - "allow", "deny": click allow / deny (for media stream infobars)
24395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      infobar_index: 0-based index of the infobar on which to perform the action
24405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: 0-based window index  Defaults to 0 (first window)
24415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: 0-based tab index.  Defaults to 0 (first tab)
24425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
24445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
24455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
24465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
24475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'PerformActionOnInfobar',
24485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'action': action,
24495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'infobar_index': infobar_index,
24505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index': tab_index,
24515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
24525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if action not in ('dismiss', 'accept', 'allow', 'deny', 'cancel'):
24535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise JSONInterfaceError('Invalid action %s' % action)
24545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=windex)
24555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetBrowserInfo(self):
24575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return info about the browser.
24585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This includes things like the version number, the executable name,
24605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    executable path, pid info about the renderer/plugin/extension processes,
24615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window dimensions. (See sample below)
24625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    For notification pid info, see 'GetActiveNotifications'.
24645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
24665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a dictionary
24675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Sample:
24695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { u'browser_pid': 93737,
24705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Child processes are the processes for plugins and other workers.
24715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'child_process_path': u'.../Chromium.app/Contents/'
24725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                'Versions/6.0.412.0/Chromium Helper.app/'
24735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                'Contents/MacOS/Chromium Helper',
24745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'child_processes': [ { u'name': u'Shockwave Flash',
24755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                u'pid': 93766,
24765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                u'type': u'Plug-in'}],
24775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'extension_views': [ {
24785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'name': u'Webpage Screenshot',
24795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'pid': 93938,
24805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'extension_id': u'dgcoklnmbeljaehamekjpeidmbicddfj',
24815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'url': u'chrome-extension://dgcoklnmbeljaehamekjpeidmbicddfj/'
24825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    'bg.html',
24835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'loaded': True,
24845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'view': {
24855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'render_process_id': 2,
24865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'render_view_id': 1},
24875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'view_type': u'EXTENSION_BACKGROUND_PAGE'}]
24885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'properties': {
24895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'BrowserProcessExecutableName': u'Chromium',
24905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'BrowserProcessExecutablePath': u'Chromium.app/Contents/MacOS/'
24915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            'Chromium',
24925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'ChromeVersion': u'6.0.412.0',
24935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'HelperProcessExecutableName': u'Chromium Helper',
24945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'HelperProcessExecutablePath': u'Chromium Helper.app/Contents/'
24955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            'MacOS/Chromium Helper',
24965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'command_line_string': "COMMAND_LINE_STRING --WITH-FLAGS",
24975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'branding': 'Chromium',
24985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'is_official': False,}
24995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # The order of the windows and tabs listed here will be the same as
25005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # what shows up on screen.
25015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'windows': [ { u'index': 0,
25025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'height': 1134,
25035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'incognito': False,
25045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'profile_path': u'Default',
25055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'fullscreen': False,
25065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'visible_page_actions':
25075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          [u'dgcoklnmbeljaehamekjpeidmbicddfj',
25085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           u'osfcklnfasdofpcldmalwpicslasdfgd']
25095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'selected_tab': 0,
25105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'tabs': [ {
25115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'index': 0,
25125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'infobars': [],
25135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'pinned': True,
25145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'renderer_pid': 93747,
25155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'url': u'http://www.google.com/' }, {
25165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'index': 1,
25175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'infobars': [],
25185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'pinned': False,
25195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'renderer_pid': 93919,
25205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'url': u'https://chrome.google.com/'}, {
25215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'index': 2,
25225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'infobars': [ {
25235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            u'buttons': [u'Allow', u'Deny'],
25245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            u'link_text': u'Learn more',
25255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            u'text': u'slides.html5rocks.com wants to track '
25265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      'your physical location',
25275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            u'type': u'confirm_infobar'}],
25285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'pinned': False,
25295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'renderer_pid': 93929,
25305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          u'url': u'http://slides.html5rocks.com/#slide14'},
25315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            ],
25325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'type': u'tabbed',
25335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'width': 925,
25345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'x': 26,
25355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'y': 44}]}
25365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
25385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
25395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
25405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
25415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetBrowserInfo',
25425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
25435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
25445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsAura(self):
25465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Is this Aura?"""
25475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.GetBrowserInfo()['properties']['aura']
25485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetProcessInfo(self):
25505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns information about browser-related processes that currently exist.
25515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This will also return information about other currently-running browsers
25535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    besides just Chrome.
25545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
25565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary containing browser-related process information as identified
25575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      by class MemoryDetails in src/chrome/browser/memory_details.h.  The
25585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dictionary contains a single key 'browsers', mapped to a list of
25595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dictionaries containing information about each browser process name.
25605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Each of those dictionaries contains a key 'processes', mapped to a list
25615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      of dictionaries containing the specific information for each process
25625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      with the given process name.
25635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The memory values given in |committed_mem| and |working_set_mem| are in
25655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      KBytes.
25665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Sample:
25685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { 'browsers': [ { 'name': 'Chromium',
25695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        'process_name': 'chrome',
25705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        'processes': [ { 'child_process_type': 'Browser',
25715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'committed_mem': { 'image': 0,
25725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                            'mapped': 0,
25735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                            'priv': 0},
25745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'is_diagnostics': False,
25755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'num_processes': 1,
25765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'pid': 7770,
25775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'product_name': '',
25785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'renderer_type': 'Unknown',
25795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'titles': [],
25805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'version': '',
25815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'working_set_mem': { 'priv': 43672,
25825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                              'shareable': 0,
25835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                              'shared': 59251}},
25845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       { 'child_process_type': 'Tab',
25855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'committed_mem': { 'image': 0,
25865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                            'mapped': 0,
25875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                            'priv': 0},
25885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'is_diagnostics': False,
25895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'num_processes': 1,
25905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'pid': 7791,
25915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'product_name': '',
25925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'renderer_type': 'Tab',
25935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'titles': ['about:blank'],
25945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'version': '',
25955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         'working_set_mem': { 'priv': 16768,
25965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                              'shareable': 0,
25975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                              'shared': 26256}},
25985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       ...<more processes>...]}]}
25995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
26015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
26025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
26035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface.
26045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetProcessInfo',
26055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
26065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
26075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNavigationInfo(self, tab_index=0, windex=0):
26095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get info about the navigation state of a given tab.
26105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
26125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: The tab index, default is 0.
26135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window_index: The window index, default is 0.
26145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
26165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a dictionary.
26175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Sample:
26185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { u'favicon_url': u'https://www.google.com/favicon.ico',
26205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'page_type': u'NORMAL_PAGE',
26215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'ssl': { u'displayed_insecure_content': False,
26225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'ran_insecure_content': False,
26235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'security_style': u'SECURITY_STYLE_AUTHENTICATED'}}
26245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Values for security_style can be:
26265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SECURITY_STYLE_UNKNOWN
26275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SECURITY_STYLE_UNAUTHENTICATED
26285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SECURITY_STYLE_AUTHENTICATION_BROKEN
26295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SECURITY_STYLE_AUTHENTICATED
26305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Values for page_type can be:
26325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NORMAL_PAGE
26335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ERROR_PAGE
26345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        INTERSTITIAL_PAGE
26355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
26365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
26375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetNavigationInfo',
26385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index': tab_index,
26395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
26405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=windex)
26415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetSecurityState(self, tab_index=0, windex=0):
26435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get security details for a given tab.
26445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
26465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: The tab index, default is 0.
26475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window_index: The window index, default is 0.
26485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
26505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a dictionary.
26515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Sample:
26525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { "security_style": SECURITY_STYLE_AUTHENTICATED,
26535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "ssl_cert_status": 3,  // bitmask of status flags
26545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "insecure_content_status": 1,  // bitmask of status flags
26555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
26565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
26575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
26585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetSecurityState',
26595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index': tab_index,
26605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
26615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
26625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
26635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetHistoryInfo(self, search_text='', windex=0):
26655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return info about browsing history.
26665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
26685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      search_text: the string to search in history.  Defaults to empty string
26695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   which means that all history would be returned. This is
26705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   functionally equivalent to searching for a text in the
26715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   chrome://history UI. So partial matches work too.
26725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   When non-empty, the history items returned will contain a
26735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   "snippet" field corresponding to the snippet visible in
26745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   the chrome://history/ UI.
26755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: index of the browser window, defaults to 0.
26765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
26785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      an instance of history_info.HistoryInfo
26795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
26805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
26815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetHistoryInfo',
26825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'search_text': search_text,
26835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
26845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return history_info.HistoryInfo(
26855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._GetResultFromJSONRequest(cmd_dict, windex=windex))
26865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def InstallExtension(self, extension_path, with_ui=False, from_webstore=None,
26885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       windex=0, tab_index=0):
26895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Installs an extension from the given path.
26905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The path must be absolute and may be a crx file or an unpacked extension
26925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    directory. Returns the extension ID if successfully installed and loaded.
26935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Otherwise, throws an exception. The extension must not already be installed.
26945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
26965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_path: The absolute path to the extension to install. If the
26975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      extension is packed, it must have a .crx extension.
26985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      with_ui: Whether the extension install confirmation UI should be shown.
26995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      from_webstore: If True, forces a .crx extension to be recognized as one
27005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          from the webstore. Can be used to force install an extension with
27015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'experimental' permissions.
27025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to 0
27035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              (first window).
27045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
27065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The ID of the installed extension.
27075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
27095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
27105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
27115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
27125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'InstallExtension',
27135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'path': extension_path,
27145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'with_ui': with_ui,
27155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'windex': windex,
27165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'tab_index': tab_index,
27175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
27185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if from_webstore:
27205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd_dict['from_webstore'] = True
27215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)['id']
27225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetExtensionsInfo(self, windex=0):
27245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns information about all installed extensions.
27255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
27275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to 0
27285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              (first window).
27295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
27315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A list of dictionaries representing each of the installed extensions.
27325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Example:
27335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [ { u'api_permissions': [u'bookmarks', u'experimental', u'tabs'],
27345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'background_url': u'',
27355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'description': u'Bookmark Manager',
27365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'effective_host_permissions': [u'chrome://favicon/*',
27375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          u'chrome://resources/*'],
27385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'host_permissions': [u'chrome://favicon/*', u'chrome://resources/*'],
27395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'id': u'eemcgdkfndhakfknompkggombfjjjeno',
27405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'is_component': True,
27415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'is_internal': False,
27425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'name': u'Bookmark Manager',
27435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'options_url': u'',
27445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'public_key': u'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQcByy+eN9jza\
27455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           zWF/DPn7NW47sW7lgmpk6eKc0BQM18q8hvEM3zNm2n7HkJv/R6f\
27465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           U+X5mtqkDuKvq5skF6qqUF4oEyaleWDFhd1xFwV7JV+/DU7bZ00\
27475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           w2+6gzqsabkerFpoP33ZRIw7OviJenP0c0uWqDWF8EGSyMhB3tx\
27485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           qhOtiQIDAQAB',
27495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'version': u'0.1' },
27505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        { u'api_permissions': [...],
27515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'background_url': u'chrome-extension://\
27525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               lkdedmbpkaiahjjibfdmpoefffnbdkli/\
27535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               background.html',
27545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'description': u'Extension which lets you read your Facebook news \
27555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            feed and wall. You can also post status updates.',
27565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'effective_host_permissions': [...],
27575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'host_permissions': [...],
27585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'id': u'lkdedmbpkaiahjjibfdmpoefffnbdkli',
27595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'name': u'Facebook for Google Chrome',
27605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'options_url': u'',
27615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'public_key': u'...',
27625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'version': u'2.0.9'
27635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'is_enabled': True,
27645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'allowed_in_incognito': True} ]
27655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
27665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
27675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetExtensionsInfo',
27685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
27695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
27705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)['extensions']
27715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def UninstallExtensionById(self, id, windex=0):
27735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Uninstall the extension with the given id.
27745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
27765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id: The string id of the extension.
27775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to 0
27785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              (first window).
27795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
27815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True, if the extension was successfully uninstalled, or
27825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      False, otherwise.
27835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
27845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
27855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'UninstallExtensionById',
27865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'id': id,
27875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
27885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
27895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)['success']
27905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetExtensionStateById(self, id, enable, allow_in_incognito, windex=0):
27925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Set extension state: enable/disable, allow/disallow in incognito mode.
27935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
27955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id: The string id of the extension.
27965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      enable: A boolean, enable extension.
27975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      allow_in_incognito: A boolean, allow extension in incognito.
27985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to 0
27995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              (first window).
28005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
28015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
28025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'SetExtensionStateById',
28035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'id': id,
28045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'enable': enable,
28055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'allow_in_incognito': allow_in_incognito,
28065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
28075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
28085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
28095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def TriggerPageActionById(self, id, tab_index=0, windex=0):
28115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Trigger page action asynchronously in the active tab.
28125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The page action icon must be displayed before invoking this function.
28145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
28165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id: The string id of the extension.
28175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: Integer index of the tab to use; defaults to 0 (first tab).
28185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to 0
28195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              (first window).
28205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
28215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
28225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'TriggerPageActionById',
28235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'id': id,
28245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
28255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index': tab_index,
28265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
28275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
28285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def TriggerBrowserActionById(self, id, tab_index=0, windex=0):
28305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Trigger browser action asynchronously in the active tab.
28315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
28335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id: The string id of the extension.
28345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: Integer index of the tab to use; defaults to 0 (first tab).
28355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to 0
28365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              (first window).
28375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
28385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
28395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'TriggerBrowserActionById',
28405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'id': id,
28415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
28425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index': tab_index,
28435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
28445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
28455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def UpdateExtensionsNow(self, windex=0):
28475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Auto-updates installed extensions.
28485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Waits until all extensions are updated, loaded, and ready for use.
28505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is equivalent to clicking the "Update extensions now" button on the
28515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chrome://extensions page.
28525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
28545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Integer index of the browser window to use; defaults to 0
28555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              (first window).
28565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
28585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation returns an error.
28595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
28605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface.
28615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'UpdateExtensionsNow',
28625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
28635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
28645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
28655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitUntilExtensionViewLoaded(self, name=None, extension_id=None,
28675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   url=None, view_type=None):
28685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Wait for a loaded extension view matching all the given properties.
28695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    If no matching extension views are found, wait for one to be loaded.
28715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    If there are more than one matching extension view, return one at random.
28725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Uses WaitUntil so timeout is capped by automation timeout.
28735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Refer to extension_view dictionary returned in GetBrowserInfo()
28745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for sample input/output values.
28755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
28775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name: (optional) Name of the extension.
28785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_id: (optional) ID of the extension.
28795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url: (optional) URL of the extension view.
28805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view_type: (optional) Type of the extension view.
28815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ['EXTENSION_BACKGROUND_PAGE'|'EXTENSION_POPUP'|'EXTENSION_INFOBAR'|
28825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         'EXTENSION_DIALOG']
28835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
28855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The 'view' property of the extension view.
28865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None, if no view loaded.
28875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
28895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation returns an error.
28905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
28915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _GetExtensionViewLoaded():
28925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_views = self.GetBrowserInfo()['extension_views']
28935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for extension_view in extension_views:
28945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ((name and name != extension_view['name']) or
28955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            (extension_id and extension_id != extension_view['extension_id']) or
28965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            (url and url != extension_view['url']) or
28975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            (view_type and view_type != extension_view['view_type'])):
28985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue
28995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if extension_view['loaded']:
29005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return extension_view['view']
29015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
29025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.WaitUntil(lambda: _GetExtensionViewLoaded()):
29045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return _GetExtensionViewLoaded()
29055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return None
29065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitUntilExtensionViewClosed(self, view):
29085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Wait for the given extension view to to be closed.
29095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Uses WaitUntil so timeout is capped by automation timeout.
29115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Refer to extension_view dictionary returned by GetBrowserInfo()
29125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for sample input value.
29135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
29155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view: 'view' property of extension view.
29165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
29185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation returns an error.
29195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
29205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _IsExtensionViewClosed():
29215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_views = self.GetBrowserInfo()['extension_views']
29225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for extension_view in extension_views:
29235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if view == extension_view['view']:
29245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return False
29255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return True
29265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.WaitUntil(lambda: _IsExtensionViewClosed())
29285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetPluginsInfo(self, windex=0):
29305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return info about plugins.
29315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is the info available from about:plugins
29335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
29355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      an instance of plugins_info.PluginsInfo
29365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
29375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return plugins_info.PluginsInfo(
29385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._GetResultFromJSONRequest({'command': 'GetPluginsInfo'},
29395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       windex=windex))
29405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def EnablePlugin(self, path):
29425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Enable the plugin at the given path.
29435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Use GetPluginsInfo() to fetch path info about a plugin.
29455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
29475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
29485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
29495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
29505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'EnablePlugin',
29515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'path': path,
29525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
29535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict)
29545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def DisablePlugin(self, path):
29565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Disable the plugin at the given path.
29575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Use GetPluginsInfo() to fetch path info about a plugin.
29595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
29615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
29625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
29635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
29645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'DisablePlugin',
29655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'path': path,
29665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
29675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict)
29685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetTabContents(self, tab_index=0, window_index=0):
29705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get the html contents of a tab (a la "view source").
29715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    As an implementation detail, this saves the html in a file, reads
29735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the file into a buffer, then deletes it.
29745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
29765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: tab index, defaults to 0.
29775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window_index: window index, defaults to 0.
29785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
29795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      html content of a page as a string.
29805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
29815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tempdir = tempfile.mkdtemp()
29825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Make it writable by chronos on chromeos
29835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.chmod(tempdir, 0777)
29845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filename = os.path.join(tempdir, 'content.html')
29855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
29865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'SaveTabContents',
29875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index': tab_index,
29885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'filename': filename
29895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
29905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=window_index)
29915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
29925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      f = open(filename)
29935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_data = f.read()
29945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      f.close()
29955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return all_data
29965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    finally:
29975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shutil.rmtree(tempdir, ignore_errors=True)
29985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AddSavedPassword(self, password_dict, windex=0):
30005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Adds the given username-password combination to the saved passwords.
30015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
30035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password_dict: a dictionary that represents a password. Example:
30045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { 'username_value': 'user@example.com',        # Required
30055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'password_value': 'test.password',           # Required
30065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'signon_realm': 'https://www.example.com/',  # Required
30075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'time': 1279317810.0,                        # Can get from time.time()
30085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'origin_url': 'https://www.example.com/login',
30095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'username_element': 'username',              # The HTML element
30105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'password_element': 'password',              # The HTML element
30115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'submit_element': 'submit',                  # The HTML element
30125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'action_target': 'https://www.example.com/login/',
30135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'blacklist': False }
30145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: window index; defaults to 0 (first window).
30155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *Blacklist notes* To blacklist a site, add a blacklist password with the
30175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    following dictionary items: origin_url, signon_realm, username_element,
30185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    password_element, action_target, and 'blacklist': True. Then all sites that
30195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    have password forms matching those are blacklisted.
30205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
30225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True if adding the password succeeded, false otherwise. In incognito
30235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mode, adding the password should fail.
30245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
30265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
30275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
30285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
30295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'AddSavedPassword',
30305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'password': password_dict
30315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
30325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(
30335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cmd_dict, windex=windex)['password_added']
30345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RemoveSavedPassword(self, password_dict, windex=0):
30365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Removes the password matching the provided password dictionary.
30375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
30395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password_dict: A dictionary that represents a password.
30405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     For an example, see the dictionary in AddSavedPassword.
30415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The window index, default is 0 (first window).
30425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
30435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
30445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'RemoveSavedPassword',
30455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'password': password_dict
30465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
30475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=windex)
30485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetSavedPasswords(self):
30505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return the passwords currently saved.
30515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
30535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A list of dictionaries representing each password. For an example
30545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dictionary see AddSavedPassword documentation. The overall structure will
30555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      be:
30565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [ {password1 dictionary}, {password2 dictionary} ]
30575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
30585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
30595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetSavedPasswords'
30605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
30615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict)['passwords']
30625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetTheme(self, crx_file_path, windex=0):
30645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Installs the given theme synchronously.
30655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    A theme file is a file with a .crx suffix, like an extension.  The theme
30675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file must be specified with an absolute path.  This method call waits until
30685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the theme is installed and will trigger the "theme installed" infobar.
30695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    If the install is unsuccessful, will throw an exception.
30705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Uses InstallExtension().
30725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
30745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The ID of the installed theme.
30755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
30775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
30785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
30795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.InstallExtension(crx_file_path, True, windex)
30805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetActiveNotifications(self):
30825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets a list of the currently active/shown HTML5 notifications.
30835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
30855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a list containing info about each active notification, with the
30865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first item in the list being the notification on the bottom of the
30875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      notification stack. The 'content_url' key can refer to a URL or a data
30885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URI. The 'pid' key-value pair may be invalid if the notification is
30895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      closing.
30905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SAMPLE:
30925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    [ { u'content_url': u'data:text/html;charset=utf-8,%3C!DOCTYPE%l%3E%0Atm...'
30935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'display_source': 'www.corp.google.com',
30945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'origin_url': 'http://www.corp.google.com/',
30955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'pid': 8505},
30965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { u'content_url': 'http://www.gmail.com/special_notification.html',
30975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'display_source': 'www.gmail.com',
30985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'origin_url': 'http://www.gmail.com/',
30995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'pid': 9291}]
31005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
31025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
31035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
31045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return [x for x in self.GetAllNotifications() if 'pid' in x]
31055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetAllNotifications(self):
31075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets a list of all active and queued HTML5 notifications.
31085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    An active notification is one that is currently shown to the user. Chrome's
31105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notification system will limit the number of notifications shown (currently
31115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    by only allowing a certain percentage of the screen to be taken up by them).
31125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    A notification will be queued if there are too many active notifications.
31135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Once other notifications are closed, another will be shown from the queue.
31145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
31165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a list containing info about each notification, with the first
31175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      item in the list being the notification on the bottom of the
31185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      notification stack. The 'content_url' key can refer to a URL or a data
31195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      URI. The 'pid' key-value pair will only be present for active
31205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      notifications.
31215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SAMPLE:
31235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    [ { u'content_url': u'data:text/html;charset=utf-8,%3C!DOCTYPE%l%3E%0Atm...'
31245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'display_source': 'www.corp.google.com',
31255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'origin_url': 'http://www.corp.google.com/',
31265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'pid': 8505},
31275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { u'content_url': 'http://www.gmail.com/special_notification.html',
31285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'display_source': 'www.gmail.com',
31295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'origin_url': 'http://www.gmail.com/'}]
31305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
31325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
31335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
31345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
31355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetAllNotifications',
31365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
31375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict)['notifications']
31385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CloseNotification(self, index):
31405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Closes the active HTML5 notification at the given index.
31415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
31435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index: the index of the notification to close. 0 refers to the
31445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             notification on the bottom of the notification stack.
31455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
31475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
31485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
31495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
31505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'CloseNotification',
31515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'index': index,
31525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
31535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict)
31545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitForNotificationCount(self, count):
31565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Waits for the number of active HTML5 notifications to reach the given
31575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    count.
31585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
31605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
31615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
31625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
31635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'WaitForNotificationCount',
31645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'count': count,
31655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
31665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict)
31675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def FindInPage(self, search_string, forward=True,
31695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 match_case=False, find_next=False,
31705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 tab_index=0, windex=0, timeout=-1):
31715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Find the match count for the given search string and search parameters.
31725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is equivalent to using the find box.
31735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
31755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      search_string: The string to find on the page.
31765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      forward: Boolean to set if the search direction is forward or backwards
31775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match_case: Boolean to set for case sensitive search.
31785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      find_next: Boolean to set to continue the search or start from beginning.
31795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: The tab index, default is 0.
31805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The window index, default is 0.
31815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout: request timeout (in milliseconds), default is -1.
31825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
31845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      number of matches found for the given search string and parameters
31855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SAMPLE:
31865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { u'match_count': 10,
31875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      u'match_left': 100,
31885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      u'match_top': 100,
31895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      u'match_right': 200,
31905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      u'match_bottom': 200}
31915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
31935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
31945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
31955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
31965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'FindInPage',
31975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index' : tab_index,
31985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'search_string' : search_string,
31995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'forward' : forward,
32005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'match_case' : match_case,
32015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'find_next' : find_next,
32025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
32035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=windex,
32045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          timeout=timeout)
32055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def OpenFindInPage(self, windex=0):
32075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Opens the "Find in Page" box.
32085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
32105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Index of the window; defaults to 0.
32115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
32135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
32145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
32155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
32165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'OpenFindInPage',
32175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex' : windex,
32185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
32195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
32205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsFindInPageVisible(self, windex=0):
32225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the visibility of the "Find in Page" box.
32235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
32255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: Index of the window; defaults to 0.
32265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
32285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A boolean indicating the visibility state of the "Find in Page" box.
32295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
32315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
32325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
32335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
32345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'IsFindInPageVisible',
32355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex' : windex,
32365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
32375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)['is_visible']
32385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AddDomEventObserver(self, event_name='', automation_id=-1,
32415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          recurring=False):
32425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Adds a DomEventObserver associated with the AutomationEventQueue.
32435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    An app raises a matching event in Javascript by calling:
32455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window.domAutomationController.sendWithId(automation_id, event_name)
32465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
32485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_name: The event name to watch for. By default an event is raised
32495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  for any message.
32505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      automation_id: The Automation Id of the sent message. By default all
32515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     messages sent from the window.domAutomationController are
32525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     observed. Note that other PyAuto functions also send
32535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     messages through window.domAutomationController with
32545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     arbirary Automation Ids and they will be observed.
32555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      recurring: If False the observer will be removed after it generates one
32565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 event, otherwise it will continue observing and generating
32575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 events until explicity removed with RemoveEventObserver(id).
32585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
32605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The id of the created observer, which can be used with GetNextEvent(id)
32615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      and RemoveEventObserver(id).
32625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
32645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
32655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
32665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
32675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'AddDomEventObserver',
32685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'event_name': event_name,
32695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'automation_id': automation_id,
32705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'recurring': recurring,
32715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
32725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)['observer_id']
32735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AddDomMutationObserver(self, mutation_type, xpath,
32755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             attribute='textContent', expected_value=None,
32765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             automation_id=44444,
32775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             exec_js=None, **kwargs):
32785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Sets up an event observer watching for a specific DOM mutation.
32795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Creates an observer that raises an event when a mutation of the given type
32815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    occurs on a DOM node specified by |selector|.
32825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
32845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mutation_type: One of 'add', 'remove', 'change', or 'exists'.
32855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      xpath: An xpath specifying the DOM node to watch. The node must already
32865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          exist if |mutation_type| is 'change'.
32875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      attribute: Attribute to match |expected_value| against, if given. Defaults
32885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          to 'textContent'.
32895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expected_value: Optional regular expression to match against the node's
32905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          textContent attribute after the mutation. Defaults to None.
32915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      automation_id: The automation_id used to route the observer javascript
32925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          messages. Defaults to 44444.
32935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      exec_js: A callable of the form f(self, js, **kwargs) used to inject the
32945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          MutationObserver javascript. Defaults to None, which uses
32955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          PyUITest.ExecuteJavascript.
32965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Any additional keyword arguments are passed on to ExecuteJavascript and
32985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      can be used to select the tab where the DOM MutationObserver is created.
32995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
33015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The id of the created observer, which can be used with GetNextEvent(id)
33025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      and RemoveEventObserver(id).
33035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
33055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
33065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JavascriptRuntimeError if the injected javascript
33075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          MutationObserver returns an error.
33085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
33095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert mutation_type in ('add', 'remove', 'change', 'exists'), \
33105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Unexpected value "%s" for mutation_type.' % mutation_type
33115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
33125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'AddDomEventObserver',
33135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'event_name': '__dom_mutation_observer__:$(id)',
33145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'automation_id': automation_id,
33155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'recurring': False,
33165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
33175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_id = (
33185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._GetResultFromJSONRequest(cmd_dict, windex=None)['observer_id'])
33195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    expected_string = ('null' if expected_value is None else '"%s"' %
33205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       expected_value.replace('"', r'\"'))
33215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jsfile = os.path.join(os.path.abspath(os.path.dirname(__file__)),
33225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          'dom_mutation_observer.js')
33235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    with open(jsfile, 'r') as f:
33245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      js = ('(' + f.read() + ')(%d, %d, "%s", "%s", "%s", %s);' %
33255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            (automation_id, observer_id, mutation_type,
33265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             xpath.replace('"', r'\"'), attribute, expected_string))
33275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    exec_js = exec_js or PyUITest.ExecuteJavascript
33285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
33295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jsreturn = exec_js(self, js, **kwargs)
33305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except JSONInterfaceError:
33315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise JSONInterfaceError('Failed to inject DOM mutation observer.')
33325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if jsreturn != 'success':
33335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.RemoveEventObserver(observer_id)
33345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise JavascriptRuntimeError(jsreturn)
33355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return observer_id
33365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitForDomNode(self, xpath, attribute='textContent',
33385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     expected_value=None, exec_js=None, timeout=-1,
33395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     msg='Expected DOM node failed to appear.', **kwargs):
33405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Waits until a node specified by an xpath exists in the DOM.
33415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTE: This does NOT poll. It returns as soon as the node appears, or
33435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      immediately if the node already exists.
33445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
33465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      xpath: An xpath specifying the DOM node to watch.
33475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      attribute: Attribute to match |expected_value| against, if given. Defaults
33485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          to 'textContent'.
33495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expected_value: Optional regular expression to match against the node's
33505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          textContent attribute. Defaults to None.
33515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      exec_js: A callable of the form f(self, js, **kwargs) used to inject the
33525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          MutationObserver javascript. Defaults to None, which uses
33535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          PyUITest.ExecuteJavascript.
33545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      msg: An optional error message used if a JSONInterfaceError is caught
33555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          while waiting for the DOM node to appear.
33565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout: Time to wait for the node to exist before raising an exception,
33575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          defaults to the default automation timeout.
33585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Any additional keyword arguments are passed on to ExecuteJavascript and
33605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      can be used to select the tab where the DOM MutationObserver is created.
33615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
33635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
33645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JavascriptRuntimeError if the injected javascript
33655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          MutationObserver returns an error.
33665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
33675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_id = self.AddDomMutationObserver('exists', xpath, attribute,
33685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              expected_value, exec_js=exec_js,
33695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              **kwargs)
33705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
33715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.GetNextEvent(observer_id, timeout=timeout)
33725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except JSONInterfaceError:
33735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise JSONInterfaceError(msg)
33745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNextEvent(self, observer_id=-1, blocking=True, timeout=-1):
33765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Waits for an observed event to occur.
33775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The returned event is removed from the Event Queue. If there is already a
33795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    matching event in the queue it is returned immediately, otherwise the call
33805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    blocks until a matching event occurs. If blocking is disabled and no
33815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    matching event is in the queue this function will immediately return None.
33825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
33845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      observer_id: The id of the observer to wait for, matches any event by
33855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   default.
33865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      blocking: If True waits until there is a matching event in the queue,
33875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if False and there is no event waiting in the queue returns None
33885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                immediately.
33895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout: Time to wait for a matching event, defaults to the default
33905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               automation timeout.
33915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
33935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Event response dictionary, or None if blocking is disabled and there is no
33945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      matching event in the queue.
33955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SAMPLE:
33965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { 'observer_id': 1,
33975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'name': 'login completed',
33985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'type': 'raised_event'}
33995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
34015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
34025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
34035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
34045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetNextEvent',
34055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'observer_id' : observer_id,
34065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'blocking' : blocking,
34075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
34085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None,
34095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          timeout=timeout)
34105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RemoveEventObserver(self, observer_id):
34125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Removes an Event Observer from the AutomationEventQueue.
34135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Expects a valid observer_id.
34155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
34175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      observer_id: The id of the observer to remove.
34185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
34205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
34215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
34225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
34235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'RemoveEventObserver',
34245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'observer_id' : observer_id,
34255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
34265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
34275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ClearEventQueue(self):
34295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Removes all events currently in the AutomationEventQueue.
34305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
34325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
34335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
34345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
34355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'ClearEventQueue',
34365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
34375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
34385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitUntilNavigationCompletes(self, tab_index=0, windex=0):
34405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Wait until the specified tab is done navigating.
34415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    It is safe to call ExecuteJavascript() as soon as the call returns. If
34435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    there is no outstanding navigation the call will return immediately.
34445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
34465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: index of the tab.
34475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: index of the window.
34485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
34505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
34515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
34525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
34535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'WaitUntilNavigationCompletes',
34545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index': tab_index,
34555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex': windex,
34565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
34575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict)
34585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExecuteJavascript(self, js, tab_index=0, windex=0, frame_xpath=''):
34605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Executes a script in the specified frame of a tab.
34615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    By default, execute the script in the top frame of the first tab in the
34635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first window. The invoked javascript function must send a result back via
34645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the domAutomationController.send function, or this function will never
34655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return.
34665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
34685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      js: script to be executed.
34695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: index of the window.
34705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: index of the tab.
34715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      frame_xpath: XPath of the frame to execute the script.  Default is no
34725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      frame. Example: '//frames[1]'.
34735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
34755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a value that was sent back via the domAutomationController.send method
34765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
34785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
34795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
34805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
34815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'ExecuteJavascript',
34825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'javascript' : js,
34835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'windex' : windex,
34845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index' : tab_index,
34855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'frame_xpath' : frame_xpath,
34865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
34875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._GetResultFromJSONRequest(cmd_dict)['result']
34885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Wrap result in an array before deserializing because valid JSON has an
34895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # array or an object as the root.
34905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    json_string = '[' + result + ']'
34915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return json.loads(json_string)[0]
34925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExecuteJavascriptInRenderView(self, js, view, frame_xpath=''):
34945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Executes a script in the specified frame of an render view.
34955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The invoked javascript function must send a result back via the
34975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    domAutomationController.send function, or this function will never return.
34985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
35005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      js: script to be executed.
35015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view: A dictionary representing a unique id for the render view as
35025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      returned for example by.
35035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.GetBrowserInfo()['extension_views'][]['view'].
35045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Example:
35055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { 'render_process_id': 1,
35065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'render_view_id' : 2}
35075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      frame_xpath: XPath of the frame to execute the script. Default is no
35095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      frame. Example:
35105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      '//frames[1]'
35115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
35135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a value that was sent back via the domAutomationController.send method
35145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
35165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
35175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
35185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
35195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'ExecuteJavascriptInRenderView',
35205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'javascript' : js,
35215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'view' : view,
35225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'frame_xpath' : frame_xpath,
35235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
35245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._GetResultFromJSONRequest(cmd_dict, windex=None)['result']
35255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Wrap result in an array before deserializing because valid JSON has an
35265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # array or an object as the root.
35275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    json_string = '[' + result + ']'
35285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return json.loads(json_string)[0]
35295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExecuteJavascriptInOOBEWebUI(self, js, frame_xpath=''):
35315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Executes a script in the specified frame of the OOBE WebUI.
35325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    By default, execute the script in the top frame of the OOBE window. This
35345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    also works for all OOBE pages, including the enterprise enrollment
35355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    screen and login page. The invoked javascript function must send a result
35365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    back via the domAutomationController.send function, or this function will
35375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    never return.
35385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
35405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      js: Script to be executed.
35415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      frame_xpath: XPath of the frame to execute the script. Default is no
35425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          frame. Example: '//frames[1]'
35435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
35455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A value that was sent back via the domAutomationController.send method.
35465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
35485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
35495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
35505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
35515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'ExecuteJavascriptInOOBEWebUI',
35525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'javascript': js,
35545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'frame_xpath': frame_xpath,
35555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
35565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._GetResultFromJSONRequest(cmd_dict, windex=None)['result']
35575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Wrap result in an array before deserializing because valid JSON has an
35585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # array or an object as the root.
35595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return json.loads('[' + result + ']')[0]
35605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetDOMValue(self, expr, tab_index=0, windex=0, frame_xpath=''):
35635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Executes a Javascript expression and returns the value.
35645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is a wrapper for ExecuteJavascript, eliminating the need to
35665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    explicitly call domAutomationController.send function.
35675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
35695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      expr: expression value to be returned.
35705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: index of the tab.
35715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: index of the window.
35725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      frame_xpath: XPath of the frame to execute the script.  Default is no
35735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      frame. Example: '//frames[1]'.
35745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
35765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a string that was sent back via the domAutomationController.send method.
35775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
35785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    js = 'window.domAutomationController.send(%s);' % expr
35795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.ExecuteJavascript(js, tab_index, windex, frame_xpath)
35805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CallJavascriptFunc(self, function, args=[], tab_index=0, windex=0):
35825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Executes a script which calls a given javascript function.
35835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The invoked javascript function must send a result back via the
35855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    domAutomationController.send function, or this function will never return.
35865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Defaults to first tab in first window.
35885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
35905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      function: name of the function.
35915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      args: list of all the arguments to pass into the called function. These
35925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            should be able to be converted to a string using the |str| function.
35935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: index of the tab within the given window.
35945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: index of the window.
35955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
35975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a string that was sent back via the domAutomationController.send method
35985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
35995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    converted_args = map(lambda arg: json.dumps(arg), args)
36005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    js = '%s(%s)' % (function, ', '.join(converted_args))
36015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug('Executing javascript: %s', js)
36025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.ExecuteJavascript(js, tab_index, windex)
36035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def HeapProfilerDump(self, process_type, reason, tab_index=0, windex=0):
360590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    """Dumps a heap profile. It works only on Linux and ChromeOS.
36065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    We need an environment variable "HEAPPROFILE" set to a directory and a
36085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filename prefix, for example, "/tmp/prof".  In a case of this example,
36095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    heap profiles will be dumped into "/tmp/prof.(pid).0002.heap",
36105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "/tmp/prof.(pid).0003.heap", and so on.  Nothing happens when this
36115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function is called without the env.
36125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
361390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    Also, this requires the --enable-memory-benchmarking command line flag.
361490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
36155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
36165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      process_type: A string which is one of 'browser' or 'renderer'.
36175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reason: A string which describes the reason for dumping a heap profile.
36185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              The reason will be included in the logged message.
36195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              Examples:
36205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'To check memory leaking'
36215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'For PyAuto tests'
36225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: tab index to work on if 'process_type' == 'renderer'.
36235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Defaults to 0 (first tab).
36245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: window index to work on if 'process_type' == 'renderer'.
36255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Defaults to 0 (first window).
36265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
36285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
36295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
36305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert process_type in ('browser', 'renderer')
36315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.IsLinux():  # IsLinux() also implies IsChromeOS().
363290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      js = """
363390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          if (!chrome.memoryBenchmarking ||
363490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)              !chrome.memoryBenchmarking.isHeapProfilerRunning()) {
363590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            domAutomationController.send('memory benchmarking disabled');
363690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          } else {
363790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            chrome.memoryBenchmarking.heapProfilerDump("%s", "%s");
363890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            domAutomationController.send('success');
363990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          }
364090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      """ % (process_type, reason.replace('"', '\\"'))
364190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      result = self.ExecuteJavascript(js, tab_index, windex)
364290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if result != 'success':
364390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        raise JSONInterfaceError('Heap profiler dump failed: ' + result)
36445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
36455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.warn('Heap-profiling is not supported in this OS.')
36465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNTPThumbnails(self):
36485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return a list of info about the sites in the NTP most visited section.
36495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SAMPLE:
36505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [{ u'title': u'Google',
36515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'url': u'http://www.google.com'},
36525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       {
36535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'title': u'Yahoo',
36545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'url': u'http://www.yahoo.com'}]
36555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
36565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetNTPInfo()['most_visited']
36575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNTPThumbnailIndex(self, thumbnail):
36595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the index of the given NTP thumbnail, or -1 if it is not shown.
36605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
36625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thumbnail: a thumbnail dict received from |GetNTPThumbnails|
36635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
36645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thumbnails = self.GetNTPThumbnails()
36655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for i in range(len(thumbnails)):
36665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if thumbnails[i]['url'] == thumbnail['url']:
36675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return i
36685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1
36695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RemoveNTPThumbnail(self, thumbnail):
36715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Removes the NTP thumbnail and returns true on success.
36725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
36745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thumbnail: a thumbnail dict received from |GetNTPThumbnails|
36755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
36765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._CheckNTPThumbnailShown(thumbnail)
36775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
36785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'RemoveNTPMostVisitedThumbnail',
36795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'url': thumbnail['url']
36805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
36815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict)
36825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RestoreAllNTPThumbnails(self):
36845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Restores all the removed NTP thumbnails.
36855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Note:
36865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      the default thumbnails may come back into the Most Visited sites
36875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      section after doing this
36885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
36895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
36905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'RestoreAllNTPMostVisitedThumbnails'
36915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
36925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict)
36935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNTPDefaultSites(self):
36955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns a list of URLs for all the default NTP sites, regardless of
36965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    whether they are showing or not.
36975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    These sites are the ones present in the NTP on a fresh install of Chrome.
36995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
37005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetNTPInfo()['default_sites']
37015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RemoveNTPDefaultThumbnails(self):
37035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Removes all thumbnails for default NTP sites, regardless of whether they
37045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    are showing or not."""
37055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'RemoveNTPMostVisitedThumbnail' }
37065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for site in self.GetNTPDefaultSites():
37075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd_dict['url'] = site
37085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._GetResultFromJSONRequest(cmd_dict)
37095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNTPRecentlyClosed(self):
37115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return a list of info about the items in the NTP recently closed section.
37125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SAMPLE:
37135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [{
37145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'type': u'tab',
37155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'url': u'http://www.bing.com',
37165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'title': u'Bing',
37175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'timestamp': 2139082.03912,  # Seconds since epoch (Jan 1, 1970)
37185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'direction': u'ltr'},
37195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       {
37205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'type': u'window',
37215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'timestamp': 2130821.90812,
37225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'tabs': [
37235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         {
37245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           u'type': u'tab',
37255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           u'url': u'http://www.cnn.com',
37265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           u'title': u'CNN',
37275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           u'timestamp': 2129082.12098,
37285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           u'direction': u'ltr'}]},
37295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       {
37305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'type': u'tab',
37315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'url': u'http://www.altavista.com',
37325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'title': u'Altavista',
37335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'timestamp': 21390820.12903,
37345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         u'direction': u'rtl'}]
37355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
37365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetNTPInfo()['recently_closed']
37375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNTPApps(self):
37395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Retrieves information about the apps listed on the NTP.
37405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    In the sample data below, the "launch_type" will be one of the following
37425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    strings: "pinned", "regular", "fullscreen", "window", or "unknown".
37435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SAMPLE:
37455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    [
37465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
37475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'app_launch_index': 2,
37485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'description': u'Web Store',
37495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'icon_big': u'chrome://theme/IDR_APP_DEFAULT_ICON',
37505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'icon_small': u'chrome://favicon/https://chrome.google.com/webstore',
37515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'id': u'ahfgeienlihckogmohjhadlkjgocpleb',
37525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'is_component_extension': True,
37535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'is_disabled': False,
37545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'launch_container': 2,
37555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'launch_type': u'regular',
37565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'launch_url': u'https://chrome.google.com/webstore',
37575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'name': u'Chrome Web Store',
37585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'options_url': u'',
37595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      },
37605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
37615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'app_launch_index': 1,
37625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'description': u'A countdown app',
37635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'icon_big': (u'chrome-extension://aeabikdlfbfeihglecobdkdflahfgcpd/'
37645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      u'countdown128.png'),
37655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'icon_small': (u'chrome://favicon/chrome-extension://'
37665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'aeabikdlfbfeihglecobdkdflahfgcpd/'
37675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'launchLocalPath.html'),
37685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'id': u'aeabikdlfbfeihglecobdkdflahfgcpd',
37695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'is_component_extension': False,
37705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'is_disabled': False,
37715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'launch_container': 2,
37725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'launch_type': u'regular',
37735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'launch_url': (u'chrome-extension://aeabikdlfbfeihglecobdkdflahfgcpd/'
37745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        u'launchLocalPath.html'),
37755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'name': u'Countdown',
37765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'options_url': u'',
37775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
37785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ]
37795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
37815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A list of dictionaries in which each dictionary contains the information
37825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for a single app that appears in the "Apps" section of the NTP.
37835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
37845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetNTPInfo()['apps']
37855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetNTPInfo(self):
37875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get info about the New Tab Page (NTP).
37885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This does not retrieve the actual info displayed in a particular NTP; it
37905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    retrieves the current state of internal data that would be used to display
37915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    an NTP.  This includes info about the apps, the most visited sites,
37925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the recently closed tabs and windows, and the default NTP sites.
37935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SAMPLE:
37955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
37965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      u'apps': [ ... ],
37975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      u'most_visited': [ ... ],
37985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      u'recently_closed': [ ... ],
37995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      u'default_sites': [ ... ]
38005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
38015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
38035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary containing all the NTP info. See details about the different
38045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sections in their respective methods: GetNTPApps(), GetNTPThumbnails(),
38055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetNTPRecentlyClosed(), and GetNTPDefaultSites().
38065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
38085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
38095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
38105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
38115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetNTPInfo',
38125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
38135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict)
38145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _CheckNTPThumbnailShown(self, thumbnail):
38165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.GetNTPThumbnailIndex(thumbnail) == -1:
38175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise NTPThumbnailNotShownError()
38185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def LaunchApp(self, app_id, windex=0):
38205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Opens the New Tab Page and launches the specified app from it.
38215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This method will not return until after the contents of a new tab for the
38235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    launched app have stopped loading.
38245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
38265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      app_id: The string ID of the app to launch.
38275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on.  Defaults to 0 (the
38285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              first window).
38295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
38315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
38325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
38335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.AppendTab(GURL('chrome://newtab'), windex)  # Also activates this tab.
38345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
38355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'LaunchApp',
38365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'id': app_id,
38375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
38385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=windex)
38395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetAppLaunchType(self, app_id, launch_type, windex=0):
38415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Sets the launch type for the specified app.
38425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
38445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      app_id: The string ID of the app whose launch type should be set.
38455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      launch_type: The string launch type, which must be one of the following:
38465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   'pinned': Launch in a pinned tab.
38475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   'regular': Launch in a regular tab.
38485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   'fullscreen': Launch in a fullscreen tab.
38495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   'window': Launch in a new browser window.
38505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: The index of the browser window to work on.  Defaults to 0 (the
38515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              first window).
38525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
38545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
38555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
38565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertTrue(launch_type in ('pinned', 'regular', 'fullscreen',
38575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    'window'),
38585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    msg='Unexpected launch type value: "%s"' % launch_type)
38595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
38605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'SetAppLaunchType',
38615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'id': app_id,
38625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'launch_type': launch_type,
38635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
38645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=windex)
38655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetV8HeapStats(self, tab_index=0, windex=0):
38675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns statistics about the v8 heap in the renderer process for a tab.
38685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
38705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: The tab index, default is 0.
38715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window_index: The window index, default is 0.
38725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
38745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary containing v8 heap statistics. Memory values are in bytes.
38755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Example:
38765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        { 'renderer_id': 6223,
38775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'v8_memory_allocated': 21803776,
38785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'v8_memory_used': 10565392 }
38795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
38805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface.
38815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetV8HeapStats',
38825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index': tab_index,
38835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
38845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=windex)
38855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetFPS(self, tab_index=0, windex=0):
38875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the current FPS associated with the renderer process for a tab.
38885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FPS is the rendered frames per second.
38905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
38925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: The tab index, default is 0.
38935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window_index: The window index, default is 0.
38945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
38965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary containing FPS info.
38975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Example:
38985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        { 'renderer_id': 23567,
38995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'routing_id': 1,
39005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'fps': 29.404298782348633 }
39015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
39025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface.
39035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetFPS',
39045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'tab_index': tab_index,
39055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
39065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=windex)
39075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsFullscreenForBrowser(self, windex=0):
39095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns true if the window is currently fullscreen and was initially
39105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    transitioned to fullscreen by a browser (vs tab) mode transition."""
39115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(
39125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { 'command': 'IsFullscreenForBrowser' },
39135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex=windex).get('result')
39145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsFullscreenForTab(self, windex=0):
39165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns true if fullscreen has been caused by a tab."""
39175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(
39185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { 'command': 'IsFullscreenForTab' },
39195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex=windex).get('result')
39205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsMouseLocked(self, windex=0):
39225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns true if the mouse is currently locked."""
39235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(
39245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { 'command': 'IsMouseLocked' },
39255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex=windex).get('result')
39265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsMouseLockPermissionRequested(self, windex=0):
39285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns true if the user is currently prompted to give permision for
39295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mouse lock."""
39305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(
39315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { 'command': 'IsMouseLockPermissionRequested' },
39325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex=windex).get('result')
39335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsFullscreenPermissionRequested(self, windex=0):
39355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns true if the user is currently prompted to give permision for
39365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fullscreen."""
39375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(
39385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { 'command': 'IsFullscreenPermissionRequested' },
39395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex=windex).get('result')
39405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsFullscreenBubbleDisplayed(self, windex=0):
39425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns true if the fullscreen and mouse lock bubble is currently
39435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    displayed."""
39445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(
39455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { 'command': 'IsFullscreenBubbleDisplayed' },
39465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex=windex).get('result')
39475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsFullscreenBubbleDisplayingButtons(self, windex=0):
39495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns true if the fullscreen and mouse lock bubble is currently
39505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    displayed and presenting buttons."""
39515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(
39525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { 'command': 'IsFullscreenBubbleDisplayingButtons' },
39535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex=windex).get('result')
39545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AcceptCurrentFullscreenOrMouseLockRequest(self, windex=0):
39565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Activate the accept button on the fullscreen and mouse lock bubble."""
39575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(
39585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { 'command': 'AcceptCurrentFullscreenOrMouseLockRequest' },
39595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex=windex)
39605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def DenyCurrentFullscreenOrMouseLockRequest(self, windex=0):
39625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Activate the deny button on the fullscreen and mouse lock bubble."""
39635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(
39645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { 'command': 'DenyCurrentFullscreenOrMouseLockRequest' },
39655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex=windex)
39665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def KillRendererProcess(self, pid):
39685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Kills the given renderer process.
39695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This will return only after the browser has received notice of the renderer
39715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    close.
39725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
39745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pid: the process id of the renderer to kill
39755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
39775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
39785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
39795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
39805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'KillRendererProcess',
39815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'pid': pid
39825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
39835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict)
39845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def NewWebDriver(self, port=0):
39865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns a new remote WebDriver instance.
39875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
39895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      port: The port to start WebDriver on; by default the service selects an
39905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            open port. It is an error to request a port number and request a
39915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            different port later.
39925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
39945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      selenium.webdriver.remote.webdriver.WebDriver instance
39955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
39965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    from chrome_driver_factory import ChromeDriverFactory
39975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global _CHROME_DRIVER_FACTORY
39985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if _CHROME_DRIVER_FACTORY is None:
39995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      _CHROME_DRIVER_FACTORY = ChromeDriverFactory(port=port)
40005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertTrue(_CHROME_DRIVER_FACTORY.GetPort() == port or port == 0,
40015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    msg='Requested a WebDriver on a specific port while already'
40025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        ' running on a different port.')
40035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return _CHROME_DRIVER_FACTORY.NewChromeDriver(self)
40045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CreateNewAutomationProvider(self, channel_id):
40065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Creates a new automation provider.
40075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The provider will open a named channel in server mode.
40095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
40105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      channel_id: the channel_id to open the server channel with
40115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
40125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
40135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'CreateNewAutomationProvider',
40145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'channel_id': channel_id
40155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
40165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict)
40175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def OpenNewBrowserWindowWithNewProfile(self):
40195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Creates a new multi-profiles user, and then opens and shows a new
40205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tabbed browser window with the new profile.
40215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is equivalent to 'Add new user' action with multi-profiles.
40235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    To account for crbug.com/108761 on Win XP, this call polls until the
40255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    profile count increments by 1.
40265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
40285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
40295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
40305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_profiles = len(self.GetMultiProfileInfo()['profiles'])
40315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
40325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'OpenNewBrowserWindowWithNewProfile'
40335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
40345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
40355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(nirnimesh): Remove when crbug.com/108761 is fixed
40365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WaitUntil(
40375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        lambda: len(self.GetMultiProfileInfo()['profiles']),
40385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        expect_retval=(num_profiles + 1))
40395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def OpenProfileWindow(self, path, num_loads=1):
40415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   """Open browser window for an existing profile.
40425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   This is equivalent to picking a profile from the multi-profile menu.
40445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   Multi-profile should be enabled and the requested profile should already
40465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   exist. Creates a new window for the given profile. Use
40475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   OpenNewBrowserWindowWithNewProfile() to create a new profile.
40485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   Args:
40505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     path: profile path of the profile to be opened.
40515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     num_loads: the number of loads to wait for, when a new browser window
40525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                is created.  Useful when restoring a window with many tabs.
40535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   """
40545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   cmd_dict = {  # Prepare command for the json interface
40555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'command': 'OpenProfileWindow',
40565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'path': path,
40575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'num_loads': num_loads,
40585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   }
40595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   return self._GetResultFromJSONRequest(cmd_dict, windex=None)
40605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetMultiProfileInfo(self):
40625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Fetch info about all multi-profile users.
40635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
40655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary.
40665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Sample:
40675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
40685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'enabled': True,
40695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'profiles': [{'name': 'First user',
40705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      'path': '/tmp/.org.chromium.Chromium.Tyx17X/Default'},
40715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     {'name': 'User 1',
40725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      'path': '/tmp/.org.chromium.Chromium.Tyx17X/profile_1'}],
40735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
40745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Profiles will be listed in the same order as visible in preferences.
40765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
40785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
40795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
40805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {  # Prepare command for the json interface
40815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'command': 'GetMultiProfileInfo'
40825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
40835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
40845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RefreshPolicies(self):
40865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Refreshes all the available policy providers.
40875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Each policy provider will reload its policy source and push the updated
40895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    policies. This call waits for the new policies to be applied; any policies
40905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    installed before this call is issued are guaranteed to be ready after it
40915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    returns.
40925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
40935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(craigdh): Determine the root cause of RefreshPolicies' flakiness.
40945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #                See crosbug.com/30221
40955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timeout = PyUITest.ActionTimeoutChanger(self, 3 * 60 * 1000)
40965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'RefreshPolicies' }
40975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
40985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SubmitForm(self, form_id, tab_index=0, windex=0, frame_xpath=''):
41005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Submits the given form ID, and returns after it has been submitted.
41015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
41035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      form_id: the id attribute of the form to submit.
41045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns: true on success.
41065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
41075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    js = """
41085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        document.getElementById("%s").submit();
41095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        window.addEventListener("unload", function() {
41105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window.domAutomationController.send("done");
41115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        });
41125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """ % form_id
41135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.ExecuteJavascript(js, tab_index, windex, frame_xpath) != 'done':
41145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
41155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Wait until the form is submitted and the page completes loading.
41165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.WaitUntil(
41175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        lambda: self.GetDOMValue('document.readyState',
41185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 tab_index, windex, frame_xpath),
41195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        expect_retval='complete')
41205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SimulateAsanMemoryBug(self):
41225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Simulates a memory bug for Address Sanitizer to catch.
41235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Address Sanitizer (if it was built it) will catch the bug and abort
41255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the process.
41265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This method returns immediately before it actually causes a crash.
41275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
41285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'SimulateAsanMemoryBug' }
41295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
41305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ## ChromeOS section
41325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetLoginInfo(self):
41345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns information about login and screen locker state.
41355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This includes things like whether a user is logged in, the username
41375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    of the logged in user, and whether the screen is locked.
41385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
41405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary.
41415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Sample:
41425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { u'is_guest': False,
41435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'is_owner': True,
41445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'email': u'example@gmail.com',
41455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'user_image': 2,  # non-negative int, 'profile', 'file'
41465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'is_screen_locked': False,
41475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'login_ui_type': 'nativeui', # or 'webui'
41485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'is_logged_in': True}
41495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
41515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
41525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
41535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'GetLoginInfo' }
41545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
41555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitForSessionManagerRestart(self, function):
41575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Call a function and wait for the ChromeOS session_manager to restart.
41585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
41605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      function: The function to call.
41615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
41625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert callable(function)
41635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pgrep_process = subprocess.Popen(['pgrep', 'session_manager'],
41645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     stdout=subprocess.PIPE)
41655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    old_pid = pgrep_process.communicate()[0].strip()
41665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function()
41675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.WaitUntil(lambda: self._IsSessionManagerReady(old_pid))
41685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _WaitForInodeChange(self, path, function):
41705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Call a function and wait for the specified file path to change.
41715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
41735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path: The file path to check for changes.
41745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      function: The function to call.
41755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
41765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert callable(function)
41775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    old_inode = os.stat(path).st_ino
41785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function()
41795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.WaitUntil(lambda: self._IsInodeNew(path, old_inode))
41805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ShowCreateAccountUI(self):
41825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Go to the account creation page.
41835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is the same as clicking the "Create Account" link on the
41855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ChromeOS login screen. Does not actually create a new account.
41865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Should be displaying the login screen to work.
41875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
41895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
41905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
41915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'ShowCreateAccountUI' }
41925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # See note below under LoginAsGuest(). ShowCreateAccountUI() logs
41935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # the user in as guest in order to access the account creation page.
41945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert self._WaitForInodeChange(
41955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._named_channel_id,
41965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        lambda: self._GetResultFromJSONRequest(cmd_dict, windex=None)), \
41975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Chrome did not reopen the testing channel after login as guest.'
41985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetUp()
41995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SkipToLogin(self, skip_image_selection=True):
42015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Skips OOBE to the login screen.
42025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Assumes that we're at the beginning of OOBE.
42045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
42065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      skip_image_selection: Boolean indicating whether the user image selection
42075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            screen should also be skipped.
42085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
42105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
42115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
42125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'SkipToLogin',
42135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 'skip_image_selection': skip_image_selection }
42145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._GetResultFromJSONRequest(cmd_dict, windex=None)
42155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert result['next_screen'] == 'login', 'Unexpected wizard transition'
42165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetOOBEScreenInfo(self):
42185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Queries info about the current OOBE screen.
42195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
42215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary with the following keys:
42225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'screen_name': The title of the current OOBE screen as a string.
42245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
42265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
42275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
42285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'GetOOBEScreenInfo' }
42295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
42305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AcceptOOBENetworkScreen(self):
42325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Accepts OOBE network screen and advances to the next one.
42335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Assumes that we're already at the OOBE network screen.
42355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
42375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary with the following keys:
42385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'next_screen': The title of the next OOBE screen as a string.
42405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
42425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
42435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
42445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'AcceptOOBENetworkScreen' }
42455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
42465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AcceptOOBEEula(self, accepted, usage_stats_reporting=False):
42485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Accepts OOBE EULA and advances to the next screen.
42495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Assumes that we're already at the OOBE EULA screen.
42515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
42535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      accepted: Boolean indicating whether the EULA should be accepted.
42545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      usage_stats_reporting: Boolean indicating whether UMA should be enabled.
42555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
42575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary with the following keys:
42585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'next_screen': The title of the next OOBE screen as a string.
42605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
42625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
42635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
42645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'AcceptOOBEEula',
42655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 'accepted': accepted,
42665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 'usage_stats_reporting': usage_stats_reporting }
42675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
42685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CancelOOBEUpdate(self):
42705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Skips update on OOBE and advances to the next screen.
42715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
42735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary with the following keys:
42745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'next_screen': The title of the next OOBE screen as a string.
42765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
42785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
42795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
42805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'CancelOOBEUpdate' }
42815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
42825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def PickUserImage(self, image):
42845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Chooses image for the newly created user.
42855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Should be called immediately after login.
42875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
42895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image_type: type of user image to choose. Possible values:
42905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        - "profile": Google profile image
42915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        - non-negative int: one of the default images
42925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
42945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary with the following keys:
42955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'next_screen': The title of the next OOBE screen as a string.
42975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
42995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
43005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
43015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'PickUserImage',
43025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 'image': image }
43035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
43045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def LoginAsGuest(self):
43065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Login to chromeos as a guest user.
43075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Waits until logged in.
43095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Should be displaying the login screen to work.
43105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
43125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
43135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
43145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'LoginAsGuest' }
43155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Currently, logging in as guest causes session_manager to
43165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # restart Chrome, which will close the testing channel.
43175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # We need to call SetUp() again to reconnect to the new channel.
43185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert self._WaitForInodeChange(
43195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._named_channel_id,
43205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        lambda: self._GetResultFromJSONRequest(cmd_dict, windex=None)), \
43215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Chrome did not reopen the testing channel after login as guest.'
43225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetUp()
43235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def Login(self, username, password, timeout=120 * 1000):
43255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Login to chromeos.
43265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Waits until logged in and browser is ready.
43285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Should be displaying the login screen to work.
43295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Note that in case of webui auth-extension-based login, gaia auth errors
43315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    will not be noticed here, because the browser has no knowledge of it. In
43325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this case the GetNextEvent automation command will always time out.
43335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Args:
43352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      username: the username to log in as.
43362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      password: the user's password.
43372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      timeout: timeout in ms; defaults to two minutes.
43382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
43395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
43405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      An error string if an error occured.
43415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None otherwise.
43425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
43445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
43455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
43465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest({'command': 'AddLoginEventObserver'},
43475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   windex=None)
43485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
43495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'SubmitLoginForm',
43505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'username': username,
43515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'password': password,
43525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
43535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
43545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.AddDomEventObserver('loginfail', automation_id=4444)
43555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
43562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if self.GetNextEvent(timeout=timeout).get('name') == 'loginfail':
43575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise JSONInterfaceError('Login denied by auth server.')
43585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except JSONInterfaceError as e:
43595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise JSONInterfaceError('Login failed. Perhaps Chrome crashed, '
43605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               'failed to start, or the login flow is '
43615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               'broken? Error message: %s' % str(e))
43625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Logout(self):
43645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Log out from ChromeOS and wait for session_manager to come up.
43655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is equivalent to pressing the 'Sign out' button from the
43675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    aura shell tray when logged in.
43685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Should be logged in to work. Re-initializes the automation channel
43705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    after logout.
43715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
43725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clear_profile_orig = self.get_clear_profile()
43735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.set_clear_profile(False)
43745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert self.GetLoginInfo()['is_logged_in'], \
43755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Trying to log out when already logged out.'
43765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _SignOut():
43775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd_dict = { 'command': 'SignOut' }
43785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._GetResultFromJSONRequest(cmd_dict, windex=None)
43795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert self.WaitForSessionManagerRestart(_SignOut), \
43805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Session manager did not restart after logout.'
43815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.__SetUp()
43825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.set_clear_profile(clear_profile_orig)
43835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def LockScreen(self):
43855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Locks the screen on chromeos.
43865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Waits until screen is locked.
43885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Should be logged in and screen should not be locked to work.
43895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
43915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
43925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
43935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'LockScreen' }
43945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
43955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def UnlockScreen(self, password):
43975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Unlocks the screen on chromeos, authenticating the user's password first.
43985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Waits until screen is unlocked.
44005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Screen locker should be active for this to work.
44015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
44035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      An error string if an error occured.
44045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None otherwise.
44055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
44075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
44085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
44095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
44105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'UnlockScreen',
44115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'password': password,
44125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
44135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._GetResultFromJSONRequest(cmd_dict, windex=None)
44145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result.get('error_string')
44155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SignoutInScreenLocker(self):
44175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Signs out of chromeos using the screen locker's "Sign out" feature.
44185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Effectively the same as clicking the "Sign out" link on the screen locker.
44205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Screen should be locked for this to work.
44215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
44235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
44245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
44255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'SignoutInScreenLocker' }
44265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert self.WaitForSessionManagerRestart(
44275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        lambda: self._GetResultFromJSONRequest(cmd_dict, windex=None)), \
44285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Session manager did not restart after logout.'
44295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.__SetUp()
44305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetBatteryInfo(self):
44325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get details about battery state.
44335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
44355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary with the following keys:
44365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'battery_is_present': bool
44385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'line_power_on': bool
44395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'battery_is_present':
44405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'battery_percentage': float (0 ~ 100)
44415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'battery_fully_charged': bool
44425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if 'line_power_on':
44435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'battery_time_to_full': int (seconds)
44445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
44455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'battery_time_to_empty': int (seconds)
44465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      If it is still calculating the time left, 'battery_time_to_full'
44485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      and 'battery_time_to_empty' will be absent.
44495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Use 'battery_fully_charged' instead of 'battery_percentage'
44515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      or 'battery_time_to_full' to determine whether the battery
44525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is fully charged, since the percentage is only approximate.
44535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Sample:
44555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        { u'battery_is_present': True,
44565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'line_power_on': False,
44575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'battery_time_to_empty': 29617,
44585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'battery_percentage': 100.0,
44595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          u'battery_fully_charged': False }
44605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
44625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
44635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
44645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'GetBatteryInfo' }
44655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
44665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetPanelInfo(self):
44685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get details about open ChromeOS panels.
44695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    A panel is actually a type of browser window, so all of
44715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this information is also available using GetBrowserInfo().
44725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
44745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary.
44755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Sample:
44765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [{ 'incognito': False,
44775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         'renderer_pid': 4820,
44785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         'title': u'Downloads',
44795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         'url': u'chrome://active-downloads/'}]
44805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
44825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
44835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
44845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    panels = []
44855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for browser in self.GetBrowserInfo()['windows']:
44865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if browser['type'] != 'panel':
44875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue
44885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      panel = {}
44905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      panels.append(panel)
44915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab = browser['tabs'][0]
44925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      panel['incognito'] = browser['incognito']
44935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      panel['renderer_pid'] = tab['renderer_pid']
44945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      panel['title'] = self.GetActiveTabTitle(browser['index'])
44955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      panel['url'] = tab['url']
44965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return panels
44985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RestoreOnline(self):
45005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the device from offline mode if GoOffline was used."""
45015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert PyUITest.IsChromeOS()
45035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Restores etherent connection
45055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stdout, stderr = self.RunSuperuserActionOnChromeOS('TeardownBackchannel')
45065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if hasattr(self, 'bc_cellular_enabled') and self.bc_cellular_enabled:
45085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.ToggleNetworkDevice('cellular', True)
45095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if hasattr(self, 'bc_wifi_enabled') and self.bc_wifi_enabled:
45105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.ToggleNetworkDevice('wifi', True)
45115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert 'RuntimeError' not in stderr, stderr
45135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GoOffline(self):
45155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Puts device in offline mode.
45165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The device is put into offline mode by disabling all network interfaces
45185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    but keeping the the wired ethernet interface up and faking shill/flimflam
45195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    into thinking there is no ethernet interface by renaming the interface.
45205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is so we can keep ssh connections over the wired connection alive.
45215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
45225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert PyUITest.IsChromeOS()
45235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_info = self.GetNetworkInfo()
45245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.bc_wifi_enabled = net_info.get('wifi_enabled')
45255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.bc_cellular_enabled = net_info.get('cellular_enabled')
45265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.bc_cellular_enabled:
45285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.ToggleNetworkDevice('cellular', False)
45295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.bc_wifi_enabled:
45305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.ToggleNetworkDevice('wifi', False)
45315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stdout, stderr = self.RunSuperuserActionOnChromeOS('SetupBackchannel')
45335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert 'RuntimeError' not in stderr, stderr
45345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNetworkInfo(self):
45365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get details about ethernet, wifi, and cellular networks on chromeos.
45375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
45395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary.
45405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Sample:
45415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { u'cellular_available': True,
45425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'cellular_enabled': False,
45435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'connected_ethernet': u'/service/ethernet_abcd',
45445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'connected_wifi': u'/service/wifi_abcd_1234_managed_none',
45455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'ethernet_available': True,
45465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'ethernet_enabled': True,
45475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'ethernet_networks':
45485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            { u'/service/ethernet_abcd':
45495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                { u'device_path': u'/device/abcdeth',
45505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'name': u'',
45515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'service_path':
45525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'/profile/default/ethernet_abcd',
45535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'status': u'Connected'}
45545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              u'network_type': pyautolib.TYPE_ETHERNET },
45555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'remembered_wifi':
45565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            { u'/service/wifi_abcd_1234_managed_none':
45575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                { u'device_path': u'',
45585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'encrypted': False,
45595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'encryption': u'',
45605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'name': u'WifiNetworkName1',
45615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'status': u'Unknown',
45625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'strength': 0},
45635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              u'network_type': pyautolib.TYPE_WIFI
45645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            },
45655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'wifi_available': True,
45665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'wifi_enabled': True,
45675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'wifi_networks':
45685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            { u'/service/wifi_abcd_1234_managed_none':
45695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                { u'device_path': u'/device/abcdwifi',
45705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'encrypted': False,
45715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'encryption': u'',
45725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'name': u'WifiNetworkName1',
45735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'status': u'Connected',
45745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  u'strength': 76},
45755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              u'/service/wifi_abcd_1234_managed_802_1x':
45765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  { u'encrypted': True,
45775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    u'encryption': u'8021X',
45785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    u'name': u'WifiNetworkName2',
45795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    u'status': u'Idle',
45805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    u'strength': 79}
45815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              u'network_type': pyautolib.TYPE_WIFI }}
45825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
45855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
45865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
45875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'GetNetworkInfo' }
45885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    network_info = self._GetResultFromJSONRequest(cmd_dict, windex=None)
45895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Remembered networks do not have /service/ prepended to the service path
45915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # even though wifi_networks does.  We want this prepended to allow for
45925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # consistency and easy string comparison with wifi_networks.
45935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    remembered_wifi = {}
45945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    network_info['remembered_wifi'] = dict([('/service/' + k, v) for k, v in
45955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      network_info['remembered_wifi'].iteritems()])
45965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return network_info
45985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetConnectedWifi(self):
46005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the SSID of the currently connected wifi network.
46015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
46035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The SSID of the connected network or None if we're not connected.
46045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
46055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    service_list = self.GetNetworkInfo()
46065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    connected_service_path = service_list.get('connected_wifi')
46075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if 'wifi_networks' in service_list and \
46085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       connected_service_path in service_list['wifi_networks']:
46095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       return service_list['wifi_networks'][connected_service_path]['name']
46105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetServicePath(self, ssid, encryption=None, timeout=30):
46125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Waits until the SSID is observed and returns its service path.
46135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
46155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ssid: String defining the SSID we are searching for.
46165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      encryption: Encryption type of the network; either None to return the
46175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  first instance of network that matches the ssid, '' for
46185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  an empty network, 'PSK', 'WEP' or '8021X'.
46195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout: Duration to wait for ssid to appear.
46205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
46225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The service path or None if SSID does not exist after timeout period.
46235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
46245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _GetServicePath():
46255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service_list = self.GetNetworkInfo().get('wifi_networks', [])
46265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for service_path, service_obj in service_list.iteritems():
46275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if not (isinstance(service_obj, dict) and
46285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'encryption' in service_obj and
46295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'name' in service_obj):
46305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue
46315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        service_encr = 'PSK' if service_obj['encryption'] in ['WPA', 'RSN']\
46335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       else service_obj['encryption']
46345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if service_obj['name'] == ssid and \
46365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           (encryption == None or service_encr == encryption):
46375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return service_path
46385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.NetworkScan()
46395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return None
46405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    service_path = self.WaitUntil(_GetServicePath, timeout=timeout,
46425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  retry_sleep=1, return_retval=True)
46435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return service_path or None
46445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def NetworkScan(self):
46465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Causes ChromeOS to scan for available wifi networks.
46475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Blocks until scanning is complete.
46495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
46515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The new list of networks obtained from GetNetworkInfo().
46525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
46545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
46555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
46565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'NetworkScan' }
46575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
46585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.GetNetworkInfo()
46595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToggleNetworkDevice(self, device, enable):
46615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Enable or disable a network device on ChromeOS.
46625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Valid device names are ethernet, wifi, cellular.
46645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
46665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
46675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
46685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
46695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'ToggleNetworkDevice',
46705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'device': device,
46715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'enable': enable,
46725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
46735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
46745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PROXY_TYPE_DIRECT = 1
46765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PROXY_TYPE_MANUAL = 2
46775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PROXY_TYPE_PAC = 3
46785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitUntilWifiNetworkAvailable(self, ssid, timeout=60, is_hidden=False):
46805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Waits until the given network is available.
46815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Routers that are just turned on may take up to 1 minute upon turning them
46835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    on to broadcast their SSID.
46845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
46865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ssid: SSID of the service we want to connect to.
46875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout: timeout (in seconds)
46885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
46905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Exception if timeout duration has been hit before wifi router is seen.
46915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
46935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True, when the wifi network is seen within the timout period.
46945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      False, otherwise.
46955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
46965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _GotWifiNetwork():
46975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Returns non-empty array if desired SSID is available.
46985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      try:
46995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return [wifi for wifi in
47005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                self.NetworkScan().get('wifi_networks', {}).values()
47015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if wifi.get('name') == ssid]
47025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      except pyauto_errors.JSONInterfaceError:
47035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Temporary fix until crosbug.com/14174 is fixed.
47045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # NetworkScan is only used in updating the list of networks so errors
47055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # thrown by it are not critical to the results of wifi tests that use
47065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # this method.
47075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return False
47085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # The hidden AP's will always be on, thus we will assume it is ready to
47105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # connect to.
47115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if is_hidden:
47125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return bool(_GotWifiNetwork())
47135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.WaitUntil(_GotWifiNetwork, timeout=timeout, retry_sleep=1)
47155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ResetProxySettingsOnChromeOS(self):
47175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Public wrapper around proxysettings teardown functions."""
47185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetSharedProxies(False)
471990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    proxy_dict = {
472090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        'mode': 'direct'
472190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
472290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    self.SetProxySettingOnChromeOS(proxy_dict)
47235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
472490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  def SetProxySettingOnChromeOS(self, proxy_config):
472590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    """Set the proxy config of the current network.
47265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Owner must be logged in for these to persist.
47285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    If user is not logged in or is logged in as non-owner or guest,
47295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proxy settings do not persist across browser restarts or login/logout.
47305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
473290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      proxy_config:   A dictionary following the format described in
473390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      prefs/proxy_config_dictionary.h.
47345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
47365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
47375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
47385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
47395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'SetProxySettings',
474090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        'proxy_config': json.dumps(proxy_config)
47415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
47425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
47435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetSharedProxies(self, value):
474590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    """Allows proxies on the shared networks.
47465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
47485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value: True/False to set and clear respectively.
47495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
47515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
47525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
47535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
47545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'SetSharedProxies',
47555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'value': value,
47565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
47575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
47585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ForgetAllRememberedNetworks(self):
47605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Forgets all networks that the device has marked as remembered."""
47615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for service in self.GetNetworkInfo()['remembered_wifi']:
47625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.ForgetWifiNetwork(service)
47635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ForgetWifiNetwork(self, service_path):
47655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Forget a remembered network by its service path.
47665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This function is equivalent to clicking the 'Forget Network' button in the
47685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chrome://settings/internet page.  This function does not indicate whether
47695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    or not forget succeeded or failed.  It is up to the caller to call
47705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetNetworkInfo to check the updated remembered_wifi list to verify the
47715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    service has been removed.
47725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
47745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service_path: Flimflam path that defines the remembered network.
47755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
47775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
47785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
47795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Usually the service_path is prepended with '/service/', such as when the
47805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # service path is retrieved from GetNetworkInfo.  ForgetWifiNetwork works
47815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # only for service paths where this has already been stripped.
47825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    service_path = service_path.split('/service/')[-1]
47835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
47845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'ForgetWifiNetwork',
47855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'service_path': service_path,
47865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
47875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None, timeout=50000)
47885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ConnectToCellularNetwork(self):
47905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Connects to the available cellular network.
47915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Blocks until connection succeeds or fails.
47935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
47955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      An error string if an error occured.
47965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None otherwise.
47975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
47995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
48005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
48015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Every device should only have one cellular network present, so we can
48025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # scan for it.
48035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cellular_networks = self.NetworkScan().get('cellular_networks', {}).keys()
48045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertTrue(cellular_networks, 'Could not find cellular service.')
48055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    service_path = cellular_networks[0]
48065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
48085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'ConnectToCellularNetwork',
48095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'service_path': service_path,
48105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
48115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._GetResultFromJSONRequest(
48125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cmd_dict, windex=None, timeout=50000)
48135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result.get('error_string')
48145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def DisconnectFromCellularNetwork(self):
48165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Disconnect from the connected cellular network.
48175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Blocks until disconnect is complete.
48195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
48215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
48225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
48235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
48245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'DisconnectFromCellularNetwork',
48255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
48265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
48275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ConnectToWifiNetwork(self, service_path, password='', shared=True):
48295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Connect to a wifi network by its service path.
48305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Blocks until connection succeeds or fails.
48325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
48345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service_path: Flimflam path that defines the wifi network.
48355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password: Passphrase for connecting to the wifi network.
48365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shared: Boolean value specifying whether the network should be shared.
48375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
48395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      An error string if an error occured.
48405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None otherwise.
48415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
48435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
48445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
48455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
48465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'ConnectToWifiNetwork',
48475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'service_path': service_path,
48485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'password': password,
48495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'shared': shared,
48505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
48515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._GetResultFromJSONRequest(
48525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cmd_dict, windex=None, timeout=50000)
48535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result.get('error_string')
48545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ConnectToHiddenWifiNetwork(self, ssid, security, password='',
48565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 shared=True, save_credentials=False):
48575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Connect to a wifi network by its service path.
48585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Blocks until connection succeeds or fails.
48605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
48625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ssid: The SSID of the network to connect to.
48635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      security: The network's security type. One of: 'SECURITY_NONE',
48645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                'SECURITY_WEP', 'SECURITY_WPA', 'SECURITY_RSN', 'SECURITY_8021X'
48655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password: Passphrase for connecting to the wifi network.
48665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shared: Boolean value specifying whether the network should be shared.
48675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      save_credentials: Boolean value specifying whether 802.1x credentials are
48685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        saved.
48695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
48715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      An error string if an error occured.
48725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None otherwise.
48735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
48755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
48765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
48775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert security in ('SECURITY_NONE', 'SECURITY_WEP', 'SECURITY_WPA',
48785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        'SECURITY_RSN', 'SECURITY_8021X')
48795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
48805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'ConnectToHiddenWifiNetwork',
48815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'ssid': ssid,
48825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'security': security,
48835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'password': password,
48845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'shared': shared,
48855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'save_credentials': save_credentials,
48865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
48875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._GetResultFromJSONRequest(
48885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cmd_dict, windex=None, timeout=50000)
48895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result.get('error_string')
48905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def DisconnectFromWifiNetwork(self):
48925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Disconnect from the connected wifi network.
48935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Blocks until disconnect is complete.
48955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
48975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
48985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
48995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
49005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'DisconnectFromWifiNetwork',
49015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
49025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
49035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AddPrivateNetwork(self,
49055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        hostname,
49065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        service_name,
49075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        provider_type,
49085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        username,
49095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        password,
49105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        cert_id='',
49115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        key=''):
49125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Add and connect to a private network.
49135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Blocks until connection succeeds or fails. This is equivalent to
49155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'Add Private Network' in the network menu UI.
49165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
49185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hostname: Server hostname for the private network.
49195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service_name: Service name that defines the private network. Do not
49205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    add multiple services with the same name.
49215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      provider_type: Types are L2TP_IPSEC_PSK and L2TP_IPSEC_USER_CERT.
49225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     Provider type OPEN_VPN is not yet supported.
49235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     Type names returned by GetPrivateNetworkInfo will
49245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     also work.
49255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      username: Username for connecting to the virtual network.
49265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password: Passphrase for connecting to the virtual network.
49275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cert_id: Certificate id for a L2TP_IPSEC_USER_CERT network.
49285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key: Pre-shared key for a L2TP_IPSEC_PSK network.
49295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
49315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      An error string if an error occured.
49325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None otherwise.
49335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
49355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
49365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
49375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
49385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'AddPrivateNetwork',
49395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'hostname': hostname,
49405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'service_name': service_name,
49415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'provider_type': provider_type,
49425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'username': username,
49435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'password': password,
49445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'cert_id': cert_id,
49455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'key': key,
49465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
49475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._GetResultFromJSONRequest(
49485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cmd_dict, windex=None, timeout=50000)
49495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result.get('error_string')
49505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetPrivateNetworkInfo(self):
49525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get details about private networks on chromeos.
49535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
49555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary including information about all remembered virtual networks
49565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      as well as the currently connected virtual network, if any.
49575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Sample:
49585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { u'connected': u'/service/vpn_123_45_67_89_test_vpn'}
49595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'/service/vpn_123_45_67_89_test_vpn':
49605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          { u'username': u'vpn_user',
49615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'name': u'test_vpn',
49625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'hostname': u'123.45.67.89',
49635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'key': u'abcde',
49645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'cert_id': u'',
49655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'password': u'zyxw123',
49665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'provider_type': u'L2TP_IPSEC_PSK'},
49675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        u'/service/vpn_111_11_11_11_test_vpn2':
49685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          { u'username': u'testerman',
49695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'name': u'test_vpn2',
49705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'hostname': u'111.11.11.11',
49715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'key': u'fghijklm',
49725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'cert_id': u'',
49735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'password': u'789mnop',
49745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            u'provider_type': u'L2TP_IPSEC_PSK'},
49755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
49775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
49785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
49795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'GetPrivateNetworkInfo' }
49805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
49815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ConnectToPrivateNetwork(self, service_path):
49835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Connect to a remembered private network by its service path.
49845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Blocks until connection succeeds or fails. The network must have been
49865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    previously added with all necessary connection details.
49875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
49895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service_path: Service name that defines the private network.
49905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
49925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      An error string if an error occured.
49935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None otherwise.
49945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
49965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
49975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
49985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
49995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'ConnectToPrivateNetwork',
50005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'service_path': service_path,
50015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
50025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._GetResultFromJSONRequest(
50035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cmd_dict, windex=None, timeout=50000)
50045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result.get('error_string')
50055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def DisconnectFromPrivateNetwork(self):
50075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Disconnect from the active private network.
50085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Expects a private network to be active.
50105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
50125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
50135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
50145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
50155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'DisconnectFromPrivateNetwork',
50165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
50175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
50185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def EnableSpokenFeedback(self, enabled):
50205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Enables or disables spoken feedback accessibility mode.
50215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
50235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      enabled: Boolean value indicating the desired state of spoken feedback.
50245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
50265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
50275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
50285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
50295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'EnableSpokenFeedback',
50305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'enabled': enabled,
50315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
50325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
50335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsSpokenFeedbackEnabled(self):
50355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Check whether spoken feedback accessibility mode is enabled.
50365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
50385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True if spoken feedback is enabled, False otherwise.
50395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
50415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
50425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
50435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'IsSpokenFeedbackEnabled', }
50445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._GetResultFromJSONRequest(cmd_dict, windex=None)
50455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result.get('spoken_feedback')
50465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetTimeInfo(self, windex=0):
50485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets info about the ChromeOS status bar clock.
50495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Set the 24-hour clock by using:
50515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.SetPrefs('settings.clock.use_24hour_clock', True)
50525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
50545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a dictionary.
50555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Sample:
50565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {u'display_date': u'Tuesday, July 26, 2011',
50575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       u'display_time': u'4:30',
50585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       u'timezone': u'America/Los_Angeles'}
50595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
50615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
50625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
50635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'GetTimeInfo' }
50645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.GetLoginInfo()['is_logged_in']:
50655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return self._GetResultFromJSONRequest(cmd_dict, windex=windex)
50665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
50675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return self._GetResultFromJSONRequest(cmd_dict, windex=None)
50685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetTimezone(self, timezone):
50705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Sets the timezone on ChromeOS. A user must be logged in.
50715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The timezone is the relative path to the timezone file in
50735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /usr/share/zoneinfo. For example, /usr/share/zoneinfo/America/Los_Angeles is
50745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'America/Los_Angeles'. For a list of valid timezones see
50755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'chrome/browser/chromeos/system/timezone_settings.cc'.
50765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This method does not return indication of success or failure.
50785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    If the timezone is it falls back to a valid timezone.
50795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
50815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
50825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
50835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
50845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'SetTimezone',
50855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'timezone': timezone,
50865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
50875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
50885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def UpdateCheck(self):
50905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Checks for a ChromeOS update. Blocks until finished updating.
50915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
50935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
50945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
50955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'UpdateCheck' }
50965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
50975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetVolumeInfo(self):
50995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the volume and whether the device is muted.
51005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
51025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a tuple.
51035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Sample:
51045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (47.763456790123456, False)
51055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
51075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
51085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
51095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'GetVolumeInfo' }
51105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
51115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetVolume(self, volume):
51135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Sets the volume on ChromeOS. Only valid if not muted.
51145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
51165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      volume: The desired volume level as a percent from 0 to 100.
51175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
51195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
51205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
51215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert volume >= 0 and volume <= 100
51225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
51235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'SetVolume',
51245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'volume': float(volume),
51255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
51265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
51275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetMute(self, mute):
51295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Sets whether ChromeOS is muted or not.
51305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
51325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mute: True to mute, False to unmute.
51335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
51355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_errors.JSONInterfaceError if the automation call returns an error.
51365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
51375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'SetMute' }
51385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = {
51395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'command': 'SetMute',
51405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'mute': mute,
51415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
51425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GetResultFromJSONRequest(cmd_dict, windex=None)
51435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # HTML Terminal
51455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def OpenCrosh(self):
51475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Open crosh.
51485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Equivalent to pressing Ctrl-Alt-t.
51505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Opens in the last active (non-incognito) window.
51515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Waits long enough for crosh to load, but does not wait for the crosh
51535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prompt. Use WaitForHtermText() for that.
51545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
51555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd_dict = { 'command': 'OpenCrosh' }
51565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._GetResultFromJSONRequest(cmd_dict, windex=None)
51575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def WaitForHtermText(self, text, msg=None, tab_index=0, windex=0):
51595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Waits for the given text in a hterm tab.
51605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Can be used to wait for the crosh> prompt or ssh prompt.
51625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This does not poll. It uses dom mutation observers to wait
51645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for the given text to show up.
51655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
51675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      text: the text to wait for. Can be a regex.
51685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      msg: the failure message to emit if the text could not be found.
51695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: the tab for the hterm tab. Default: 0.
51705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: the window index for the hterm tab. Default: 0.
51715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
51725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.WaitForDomNode(
51735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        xpath='//*[contains(text(), "%s")]' % text, frame_xpath='//iframe',
51745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        msg=msg, tab_index=tab_index, windex=windex)
51755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetHtermRowsText(self, start, end, tab_index=0, windex=0):
51775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Fetch rows from a html terminal tab.
51785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Works for both crosh and ssh tab.
51805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Uses term_.getRowsText(start, end) javascript call.
51815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
51835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start: start line number (0-based).
51845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      end: the end line (one beyond the line of interest).
51855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: the tab for the hterm tab. Default: 0.
51865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: the window index for the hterm tab. Default: 0.
51875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
51885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.ExecuteJavascript(
51895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'domAutomationController.send(term_.getRowsText(%d, %d))' % (
51905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            start, end),
51915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tab_index=tab_index, windex=windex)
51925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SendKeysToHterm(self, text, tab_index=0, windex=0):
51945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Send keys to a html terminal tab.
51955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Works for both crosh and ssh tab.
51975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Uses term_.onVTKeystroke(str) javascript call.
51985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
52005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      text: the text to send.
52015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_index: the tab for the hterm tab. Default: 0.
52025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windex: the window index for the hterm tab. Default: 0.
52035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
52045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.ExecuteJavascript(
52055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'term_.onVTKeystroke("%s");'
52065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'domAutomationController.send("done")' % text,
52075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tab_index=tab_index, windex=windex)
52085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetMemoryStatsChromeOS(self, duration):
52115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Identifies and returns different kinds of current memory usage stats.
52125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This function samples values each second for |duration| seconds, then
52145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outputs the min, max, and ending values for each measurement type.
52155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
52175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      duration: The number of seconds to sample data before outputting the
52185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          minimum, maximum, and ending values for each measurement type.
52195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
52215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dictionary containing memory usage information.  Each measurement type
52225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is associated with the min, max, and ending values from among all
52235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sampled values.  Values are specified in KB.
52245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
52255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'gem_obj': {  # GPU memory usage.
52265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'min': ...,
52275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'max': ...,
52285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'end': ...,
52295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        },
52305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'gtt': { ... },  # GPU memory usage (graphics translation table).
52315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'mem_free': { ... },  # CPU free memory.
52325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'mem_available': { ... },  # CPU available memory.
52335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'mem_shared': { ... },  # CPU shared memory.
52345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'mem_cached': { ... },  # CPU cached memory.
52355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'mem_anon': { ... },  # CPU anon memory (active + inactive).
52365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'mem_file': { ... },  # CPU file memory (active + inactive).
52375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'mem_slab': { ... },  # CPU slab memory.
52385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'browser_priv': { ... },  # Chrome browser private memory.
52395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'browser_shared': { ... },  # Chrome browser shared memory.
52405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'gpu_priv': { ... },  # Chrome GPU private memory.
52415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'gpu_shared': { ... },  # Chrome GPU shared memory.
52425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'renderer_priv': { ... },  # Total private memory of all renderers.
52435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'renderer_shared': { ... },  # Total shared memory of all renderers.
52445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
52455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
52465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug('Sampling memory information for %d seconds...' % duration)
52475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stats = {}
52485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for _ in xrange(duration):
52505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # GPU memory.
52515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gem_obj_path = '/sys/kernel/debug/dri/0/i915_gem_objects'
52525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if os.path.exists(gem_obj_path):
52535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p = subprocess.Popen('grep bytes %s' % gem_obj_path,
52545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             stdout=subprocess.PIPE, shell=True)
52555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stdout = p.communicate()[0]
52565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gem_obj = re.search(
52585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            '\d+ objects, (\d+) bytes\n', stdout).group(1)
52595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if 'gem_obj' not in stats:
52605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          stats['gem_obj'] = []
52615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stats['gem_obj'].append(int(gem_obj) / 1024.0)
52625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtt_path = '/sys/kernel/debug/dri/0/i915_gem_gtt'
52645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if os.path.exists(gtt_path):
52655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p = subprocess.Popen('grep bytes %s' % gtt_path,
52665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             stdout=subprocess.PIPE, shell=True)
52675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stdout = p.communicate()[0]
52685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gtt = re.search(
52705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'Total [\d]+ objects, ([\d]+) bytes', stdout).group(1)
52715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if 'gtt' not in stats:
52725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          stats['gtt'] = []
52735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stats['gtt'].append(int(gtt) / 1024.0)
52745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # CPU memory.
52765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stdout = ''
52775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      with open('/proc/meminfo') as f:
52785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stdout = f.read()
52795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mem_free = re.search('MemFree:\s*([\d]+) kB', stdout).group(1)
52805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'mem_free' not in stats:
52825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stats['mem_free'] = []
52835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stats['mem_free'].append(int(mem_free))
52845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mem_dirty = re.search('Dirty:\s*([\d]+) kB', stdout).group(1)
52865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mem_active_file = re.search(
52875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'Active\(file\):\s*([\d]+) kB', stdout).group(1)
52885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mem_inactive_file = re.search(
52895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'Inactive\(file\):\s*([\d]+) kB', stdout).group(1)
52905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      with open('/proc/sys/vm/min_filelist_kbytes') as f:
52925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mem_min_file = f.read()
52935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Available memory =
52955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #     MemFree + ActiveFile + InactiveFile - DirtyMem - MinFileMem
52965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'mem_available' not in stats:
52975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stats['mem_available'] = []
52985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stats['mem_available'].append(
52995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          int(mem_free) + int(mem_active_file) + int(mem_inactive_file) -
53005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          int(mem_dirty) - int(mem_min_file))
53015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mem_shared = re.search('Shmem:\s*([\d]+) kB', stdout).group(1)
53035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'mem_shared' not in stats:
53045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stats['mem_shared'] = []
53055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stats['mem_shared'].append(int(mem_shared))
53065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mem_cached = re.search('Cached:\s*([\d]+) kB', stdout).group(1)
53085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'mem_cached' not in stats:
53095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stats['mem_cached'] = []
53105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stats['mem_cached'].append(int(mem_cached))
53115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mem_anon_active = re.search('Active\(anon\):\s*([\d]+) kB',
53135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  stdout).group(1)
53145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mem_anon_inactive = re.search('Inactive\(anon\):\s*([\d]+) kB',
53155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    stdout).group(1)
53165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'mem_anon' not in stats:
53175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stats['mem_anon'] = []
53185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stats['mem_anon'].append(int(mem_anon_active) + int(mem_anon_inactive))
53195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mem_file_active = re.search('Active\(file\):\s*([\d]+) kB',
53215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  stdout).group(1)
53225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mem_file_inactive = re.search('Inactive\(file\):\s*([\d]+) kB',
53235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    stdout).group(1)
53245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'mem_file' not in stats:
53255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stats['mem_file'] = []
53265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stats['mem_file'].append(int(mem_file_active) + int(mem_file_inactive))
53275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mem_slab = re.search('Slab:\s*([\d]+) kB', stdout).group(1)
53295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'mem_slab' not in stats:
53305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stats['mem_slab'] = []
53315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stats['mem_slab'].append(int(mem_slab))
53325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Chrome process memory.
53345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pinfo = self.GetProcessInfo()['browsers'][0]['processes']
53355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      total_renderer_priv = 0
53365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      total_renderer_shared = 0
53375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for process in pinfo:
53385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mem_priv = process['working_set_mem']['priv']
53395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mem_shared = process['working_set_mem']['shared']
53405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if process['child_process_type'] == 'Browser':
53415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if 'browser_priv' not in stats:
53425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            stats['browser_priv'] = []
53435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            stats['browser_priv'].append(int(mem_priv))
53445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if 'browser_shared' not in stats:
53455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            stats['browser_shared'] = []
53465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            stats['browser_shared'].append(int(mem_shared))
53475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        elif process['child_process_type'] == 'GPU':
53485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if 'gpu_priv' not in stats:
53495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            stats['gpu_priv'] = []
53505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            stats['gpu_priv'].append(int(mem_priv))
53515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if 'gpu_shared' not in stats:
53525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            stats['gpu_shared'] = []
53535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            stats['gpu_shared'].append(int(mem_shared))
53545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        elif process['child_process_type'] == 'Tab':
53555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          # Sum the memory of all renderer processes.
53565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          total_renderer_priv += int(mem_priv)
53575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          total_renderer_shared += int(mem_shared)
53585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'renderer_priv' not in stats:
53595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stats['renderer_priv'] = []
53605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stats['renderer_priv'].append(int(total_renderer_priv))
53615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'renderer_shared' not in stats:
53625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stats['renderer_shared'] = []
53635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stats['renderer_shared'].append(int(total_renderer_shared))
53645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      time.sleep(1)
53665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Compute min, max, and ending values to return.
53685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = {}
53695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for measurement_type in stats:
53705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values = stats[measurement_type]
53715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result[measurement_type] = {
53725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'min': min(values),
53735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'max': max(values),
53745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'end': values[-1],
53755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
53765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result
53785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ## ChromeOS section -- end
53805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ExtraBrowser(PyUITest):
53835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Launches a new browser with some extra flags.
53845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  The new browser is launched with its own fresh profile.
53865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  This class does not apply to ChromeOS.
53875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
53885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, chrome_flags=[], methodName='runTest', **kwargs):
53895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Accepts extra chrome flags for launching a new browser instance.
53905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
53925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome_flags: list of extra flags when launching a new browser.
53935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
53945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert not PyUITest.IsChromeOS(), \
53955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'This function cannot be used to launch a new browser in ChromeOS.'
53965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PyUITest.__init__(self, methodName=methodName, **kwargs)
53975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._chrome_flags = chrome_flags
53985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PyUITest.setUp(self)
53995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __del__(self):
54015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Tears down the browser and then calls super class's destructor"""
54025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PyUITest.tearDown(self)
54035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PyUITest.__del__(self)
54045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExtraChromeFlags(self):
54065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Prepares the browser to launch with specified Chrome flags."""
54075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PyUITest.ExtraChromeFlags(self) + self._chrome_flags
54085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class _RemoteProxy():
54115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Class for PyAuto remote method calls.
54125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Use this class along with RemoteHost.testRemoteHost to establish a PyAuto
54145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connection with another machine and make remote PyAuto calls. The RemoteProxy
54155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mimics a PyAuto object, so all json-style PyAuto calls can be made on it.
54165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  The remote host acts as a dumb executor that receives method call requests,
54185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  executes them, and sends all of the results back to the RemoteProxy, including
54195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  the return value, thrown exceptions, and console output.
54205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  The remote host should be running the same version of PyAuto as the proxy.
54225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  A mismatch could lead to undefined behavior.
54235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Example usage:
54255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    class MyTest(pyauto.PyUITest):
54265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      def testRemoteExample(self):
54275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        remote = pyauto._RemoteProxy(('127.0.0.1', 7410))
54285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        remote.NavigateToURL('http://www.google.com')
54295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        title = remote.GetActiveTabTitle()
54305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.assertEqual(title, 'Google')
54315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
54325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class RemoteException(Exception):
54335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pass
54345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, host):
54365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.RemoteConnect(host)
54375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RemoteConnect(self, host):
54395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    begin = time.time()
54405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while time.time() - begin < 50:
54415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._socket = socket.socket()
54425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not self._socket.connect_ex(host):
54435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break
54445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      time.sleep(0.25)
54455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
54465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Make one last attempt, but raise a socket error on failure.
54475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._socket = socket.socket()
54485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._socket.connect(host)
54495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RemoteDisconnect(self):
54515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._socket:
54525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._socket.shutdown(socket.SHUT_RDWR)
54535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._socket.close()
54545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._socket = None
54555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CreateTarget(self, target):
54575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Registers the methods and creates a remote instance of a target.
54585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Any RPC calls will then be made on the remote target instance. Note that the
54605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    remote instance will be a brand new instance and will have none of the state
54615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    of the local instance. The target's class should have a constructor that
54625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    takes no arguments.
54635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
54645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._Call('CreateTarget', target.__class__)
54655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._RegisterClassMethods(target)
54665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _RegisterClassMethods(self, remote_class):
54685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Make remote-call versions of all remote_class methods.
54695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for method_name, _ in inspect.getmembers(remote_class, inspect.ismethod):
54705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Ignore private methods and duplicates.
54715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if method_name[0] in string.letters and \
54725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        getattr(self, method_name, None) is None:
54735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        setattr(self, method_name, functools.partial(self._Call, method_name))
54745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _Call(self, method_name, *args, **kwargs):
54765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Send request.
54775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request = pickle.dumps((method_name, args, kwargs))
54785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._socket.send(request) != len(request):
54795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise self.RemoteException('Error sending remote method call request.')
54805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Receive response.
54825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    response = self._socket.recv(4096)
54835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not response:
54845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise self.RemoteException('Client disconnected during method call.')
54855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result, stdout, stderr, exception = pickle.loads(response)
54865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Print any output the client captured, throw any exceptions, and return.
54885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.stdout.write(stdout)
54895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.stderr.write(stderr)
54905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if exception:
54915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise self.RemoteException('%s raised by remote client: %s' %
54925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 (exception[0], exception[1]))
54935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result
54945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PyUITestSuite(pyautolib.PyUITestSuiteBase, unittest.TestSuite):
54975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Base TestSuite for PyAuto UI tests."""
54985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, args):
55005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pyautolib.PyUITestSuiteBase.__init__(self, args)
55015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Figure out path to chromium binaries
55035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_dir = os.path.normpath(os.path.dirname(pyautolib.__file__))
55045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug('Loading pyauto libs from %s', browser_dir)
55055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.InitializeWithPath(pyautolib.FilePath(browser_dir))
55065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.environ['PATH'] = browser_dir + os.pathsep + os.environ['PATH']
55075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unittest.TestSuite.__init__(self)
55095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cr_source_root = os.path.normpath(os.path.join(
55105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        os.path.dirname(__file__), os.pardir, os.pardir, os.pardir))
55115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetCrSourceRoot(pyautolib.FilePath(cr_source_root))
55125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Start http server, if needed.
55145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global _OPTIONS
55155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if _OPTIONS and not _OPTIONS.no_http_server:
55165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._StartHTTPServer()
55175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if _OPTIONS and _OPTIONS.remote_host:
55185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._ConnectToRemoteHosts(_OPTIONS.remote_host.split(','))
55195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __del__(self):
55215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # python unittest module is setup such that the suite gets deleted before
55225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # the test cases, which is odd because our test cases depend on
55235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # initializtions like exitmanager, autorelease pool provided by the
55245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # suite. Forcibly delete the test cases before the suite.
55255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    del self._tests
55265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pyautolib.PyUITestSuiteBase.__del__(self)
55275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global _HTTP_SERVER
55295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if _HTTP_SERVER:
55305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._StopHTTPServer()
55315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global _CHROME_DRIVER_FACTORY
55335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if _CHROME_DRIVER_FACTORY is not None:
55345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      _CHROME_DRIVER_FACTORY.Stop()
55355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _StartHTTPServer(self):
55375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Start a local file server hosting data files over http://"""
55385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global _HTTP_SERVER
55395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert not _HTTP_SERVER, 'HTTP Server already started'
55405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    http_data_dir = _OPTIONS.http_data_dir
5541c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    http_server = pyautolib.SpawnedTestServer(
5542c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        pyautolib.SpawnedTestServer.TYPE_HTTP,
5543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        '127.0.0.1',
5544c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        pyautolib.FilePath(http_data_dir))
55455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert http_server.Start(), 'Could not start http server'
55465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _HTTP_SERVER = http_server
55475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug('Started http server at "%s".', http_data_dir)
55485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _StopHTTPServer(self):
55505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Stop the local http server."""
55515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global _HTTP_SERVER
55525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert _HTTP_SERVER, 'HTTP Server not yet started'
55535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert _HTTP_SERVER.Stop(), 'Could not stop http server'
55545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _HTTP_SERVER = None
55555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug('Stopped http server.')
55565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _ConnectToRemoteHosts(self, addresses):
55585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Connect to remote PyAuto instances using a RemoteProxy.
55595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The RemoteHost instances must already be running."""
55615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global _REMOTE_PROXY
55625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert not _REMOTE_PROXY, 'Already connected to a remote host.'
55635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _REMOTE_PROXY = []
55645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for address in addresses:
55655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if address == 'localhost' or address == '127.0.0.1':
55665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._StartLocalRemoteHost()
55675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      _REMOTE_PROXY.append(_RemoteProxy((address, 7410)))
55685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _StartLocalRemoteHost(self):
55705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Start a remote PyAuto instance on the local machine."""
55715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Add the path to our main class to the RemoteHost's
55725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # environment, so it can load that class at runtime.
55735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    import __main__
55745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    main_path = os.path.dirname(__main__.__file__)
55755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    env = os.environ
55765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if env.get('PYTHONPATH', None):
55775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      env['PYTHONPATH'] += ':' + main_path
55785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
55795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      env['PYTHONPATH'] = main_path
55805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Run it!
55825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    subprocess.Popen([sys.executable, os.path.join(os.path.dirname(__file__),
55835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   'remote_host.py')], env=env)
55845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class _GTestTextTestResult(unittest._TextTestResult):
55875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """A test result class that can print formatted text results to a stream.
55885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Results printed in conformance with gtest output format, like:
55905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [ RUN        ] autofill.AutofillTest.testAutofillInvalid: "test desc."
55915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [         OK ] autofill.AutofillTest.testAutofillInvalid
55925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [ RUN        ] autofill.AutofillTest.testFillProfile: "test desc."
55935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [         OK ] autofill.AutofillTest.testFillProfile
55945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [ RUN        ] autofill.AutofillTest.testFillProfileCrazyCharacters: "Test."
55955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [         OK ] autofill.AutofillTest.testFillProfileCrazyCharacters
55965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
55975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, stream, descriptions, verbosity):
55985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
55995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetTestURI(self, test):
56015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if sys.version_info[:2] <= (2, 4):
56025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '%s.%s' % (unittest._strclass(test.__class__),
56035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        test._TestCase__testMethodName)
56045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '%s.%s.%s' % (test.__class__.__module__,
56055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         test.__class__.__name__,
56065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         test._testMethodName)
56075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def getDescription(self, test):
56095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '%s: "%s"' % (self._GetTestURI(test), test.shortDescription())
56105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def startTest(self, test):
56125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unittest.TestResult.startTest(self, test)
56135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.stream.writeln('[ RUN        ] %s' % self.getDescription(test))
56145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def addSuccess(self, test):
56165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unittest.TestResult.addSuccess(self, test)
56175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.stream.writeln('[         OK ] %s' % self._GetTestURI(test))
56185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def addError(self, test, err):
56205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unittest.TestResult.addError(self, test, err)
56215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.stream.writeln('[      ERROR ] %s' % self._GetTestURI(test))
56225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def addFailure(self, test, err):
56245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unittest.TestResult.addFailure(self, test, err)
56255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.stream.writeln('[     FAILED ] %s' % self._GetTestURI(test))
56265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PyAutoTextTestRunner(unittest.TextTestRunner):
56295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Test Runner for PyAuto tests that displays results in textual format.
56305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Results are displayed in conformance with gtest output.
56325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
56335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, verbosity=1):
56345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unittest.TextTestRunner.__init__(self,
56355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     stream=sys.stderr,
56365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     verbosity=verbosity)
56375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _makeResult(self):
56395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return _GTestTextTestResult(self.stream, self.descriptions, self.verbosity)
56405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Implementation inspired from unittest.main()
56435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Main(object):
56445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Main program for running PyAuto tests."""
56455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _options, _args = None, None
56475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _tests_filename = 'PYAUTO_TESTS'
56485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _platform_map = {
56495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'win32':  'win',
56505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'darwin': 'mac',
56515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'linux2': 'linux',
56525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'linux3': 'linux',
56535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'chromeos': 'chromeos',
56545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
56555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
56575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._ParseArgs()
56585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._Run()
56595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _ParseArgs(self):
56615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Parse command line args."""
56625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser = optparse.OptionParser()
56635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option(
56645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '', '--channel-id', type='string', default='',
56655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        help='Name of channel id, if using named interface.')
56665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option(
56675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '', '--chrome-flags', type='string', default='',
56685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        help='Flags passed to Chrome.  This is in addition to the usual flags '
56695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             'like suppressing first-run dialogs, enabling automation.  '
56705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             'See chrome/common/chrome_switches.cc for the list of flags '
56715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             'chrome understands.')
56725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option(
56735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '', '--http-data-dir', type='string',
56745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        default=os.path.join('chrome', 'test', 'data'),
56755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        help='Relative path from which http server should serve files.')
56765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option(
56775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '-L', '--list-tests', action='store_true', default=False,
56785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        help='List all tests, and exit.')
56795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option(
56805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '--shard',
56815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        help='Specify sharding params. Example: 1/3 implies split the list of '
56825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             'tests into 3 groups of which this is the 1st.')
56835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option(
56845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '', '--log-file', type='string', default=None,
56855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        help='Provide a path to a file to which the logger will log')
56865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option(
56875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '', '--no-http-server', action='store_true', default=False,
56885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        help='Do not start an http server to serve files in data dir.')
56895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option(
56905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '', '--remote-host', type='string', default=None,
56915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        help='Connect to remote hosts for remote automation. If "localhost" '
56925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            '"127.0.0.1" is specified, a remote host will be launched '
56935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'automatically on the local machine.')
56945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option(
56955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '', '--repeat', type='int', default=1,
56965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        help='Number of times to repeat the tests. Useful to determine '
56975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             'flakiness. Defaults to 1.')
56985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option(
56995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '-S', '--suite', type='string', default='FULL',
57005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        help='Name of the suite to load.  Defaults to "FULL".')
57015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option(
57025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '-v', '--verbose', action='store_true', default=False,
57035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        help='Make PyAuto verbose.')
57045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option(
57055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        '-D', '--wait-for-debugger', action='store_true', default=False,
57065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        help='Block PyAuto on startup for attaching debugger.')
57075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._options, self._args = parser.parse_args()
57095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global _OPTIONS
57105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _OPTIONS = self._options  # Export options so other classes can access.
57115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Set up logging. All log messages will be prepended with a timestamp.
57135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    format = '%(asctime)s %(levelname)-8s %(message)s'
57145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    level = logging.INFO
57165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.verbose:
57175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      level=logging.DEBUG
57185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.basicConfig(level=level, format=format,
57205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        filename=self._options.log_file)
57215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def TestsDir(self):
57235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the path to dir containing tests.
57245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This is typically the dir containing the tests description file.
57265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This method should be overridden by derived class to point to other dirs
57275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if needed.
57285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
57295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return os.path.dirname(__file__)
57305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
57325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _ImportTestsFromName(name):
57335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get a list of all test names from the given string.
57345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
57365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name: dot-separated string for a module, a test case or a test method.
57375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            Examples: omnibox  (a module)
57385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      omnibox.OmniboxTest  (a test case)
57395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      omnibox.OmniboxTest.testA  (a test method)
57405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
57425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [omnibox.OmniboxTest.testA, omnibox.OmniboxTest.testB, ...]
57435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
57445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _GetTestsFromTestCase(class_obj):
57455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """Return all test method names from given class object."""
57465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return [class_obj.__name__ + '.' + x for x in dir(class_obj) if
57475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              x.startswith('test')]
57485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _GetTestsFromModule(module):
57505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """Return all test method names from the given module object."""
57515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tests = []
57525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for name in dir(module):
57535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        obj = getattr(module, name)
57545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (isinstance(obj, (type, types.ClassType)) and
57555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            issubclass(obj, PyUITest) and obj != PyUITest):
57565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          tests.extend([module.__name__ + '.' + x for x in
57575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        _GetTestsFromTestCase(obj)])
57585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return tests
57595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    module = None
57615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Locate the module
57625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts = name.split('.')
57635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts_copy = parts[:]
57645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while parts_copy:
57655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      try:
57665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        module = __import__('.'.join(parts_copy))
57675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break
57685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      except ImportError:
57695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        del parts_copy[-1]
57705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if not parts_copy: raise
57715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # We have the module. Pick the exact test method or class asked for.
57725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts = parts[1:]
57735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    obj = module
57745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for part in parts:
57755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      obj = getattr(obj, part)
57765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if type(obj) == types.ModuleType:
57785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return _GetTestsFromModule(obj)
57795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif (isinstance(obj, (type, types.ClassType)) and
57805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          issubclass(obj, PyUITest) and obj != PyUITest):
57815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return [module.__name__ + '.' + x for x in _GetTestsFromTestCase(obj)]
57825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif type(obj) == types.UnboundMethodType:
57835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return [name]
57845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
57855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.warn('No tests in "%s"', name)
57865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return []
57875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _HasTestCases(self, module_string):
57895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Determines if we have any PyUITest test case classes in the module
57905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       identified by |module_string|."""
57915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    module = __import__(module_string)
57925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for name in dir(module):
57935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      obj = getattr(module, name)
57945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (isinstance(obj, (type, types.ClassType)) and
57955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          issubclass(obj, PyUITest)):
57965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return True
57975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return False
57985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _ExpandTestNames(self, args):
58005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns a list of tests loaded from the given args.
58015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The given args can be either a module (ex: module1) or a testcase
58035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (ex: module2.MyTestCase) or a test (ex: module1.MyTestCase.testX)
58045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    or a suite name (ex: @FULL). If empty, the tests in the already imported
58055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    modules are loaded.
58065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
58085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      args: [module1, module2, module3.testcase, module4.testcase.testX]
58095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            These modules or test cases or tests should be importable.
58105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            Suites can be specified by prefixing @. Example: @FULL
58115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Returns:
58135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        a list of expanded test names.  Example:
58145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          [
58155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'module1.TestCase1.testA',
58165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'module1.TestCase1.testB',
58175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'module2.TestCase2.testX',
58185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'module3.testcase.testY',
58195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'module4.testcase.testX'
58205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ]
58215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
58225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _TestsFromDescriptionFile(suite):
58245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_tests_file = os.path.join(self.TestsDir(), self._tests_filename)
58255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if suite:
58265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.debug("Reading %s (@%s)", pyauto_tests_file, suite)
58275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
58285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.debug("Reading %s", pyauto_tests_file)
58295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not os.path.exists(pyauto_tests_file):
58305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.warn("%s missing. Cannot load tests.", pyauto_tests_file)
58315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return []
58325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
58335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return self._ExpandTestNamesFrom(pyauto_tests_file, suite)
58345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not args:  # Load tests ourselves
58365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._HasTestCases('__main__'):    # we are running a test script
58375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        module_name = os.path.splitext(os.path.basename(sys.argv[0]))[0]
58385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        args.append(module_name)   # run the test cases found in it
58395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:  # run tests from the test description file
58405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        args = _TestsFromDescriptionFile(self._options.suite)
58415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:  # Check args with @ prefix for suites
58425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      out_args = []
58435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for arg in args:
58445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if arg.startswith('@'):
58455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          suite = arg[1:]
58465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          out_args += _TestsFromDescriptionFile(suite)
58475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
58485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          out_args.append(arg)
58495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      args = out_args
58505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return args
58515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _ExpandTestNamesFrom(self, filename, suite):
58535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Load test names from the given file.
58545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
58565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      filename: the file to read the tests from
58575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      suite: the name of the suite to load from |filename|.
58585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
58605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a list of test names
58615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [module.testcase.testX, module.testcase.testY, ..]
58625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
58635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    suites = PyUITest.EvalDataFrom(filename)
58645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    platform = sys.platform
58655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if PyUITest.IsChromeOS():  # check if it's chromeos
58665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      platform = 'chromeos'
58675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert platform in self._platform_map, '%s unsupported' % platform
58685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _NamesInSuite(suite_name):
58695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.debug('Expanding suite %s', suite_name)
58705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      platforms = suites.get(suite_name)
58715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      names = platforms.get('all', []) + \
58725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              platforms.get(self._platform_map[platform], [])
58735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = []
58745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Recursively include suites if any.  Suites begin with @.
58755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for name in names:
58765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if name.startswith('@'):  # Include another suite
58775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ret.extend(_NamesInSuite(name[1:]))
58785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
58795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ret.append(name)
58805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ret
58815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert suite in suites, '%s: No such suite in %s' % (suite, filename)
58835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_names = _NamesInSuite(suite)
58845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    args = []
58855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    excluded = []
58865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Find all excluded tests.  Excluded tests begin with '-'.
58875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for name in all_names:
58885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if name.startswith('-'):  # Exclude
58895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        excluded.extend(self._ImportTestsFromName(name[1:]))
58905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
58915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        args.extend(self._ImportTestsFromName(name))
58925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for name in excluded:
58935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if name in args:
58945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        args.remove(name)
58955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
58965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.warn('Cannot exclude %s. Not included. Ignoring', name)
58975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if excluded:
58985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.debug('Excluded %d test(s): %s', len(excluded), excluded)
58995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return args
59005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
59015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _Run(self):
59025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Run the tests."""
59035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.wait_for_debugger:
59045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raw_input('Attach debugger to process %s and hit <enter> ' % os.getpid())
59055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
59065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    suite_args = [sys.argv[0]]
59075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chrome_flags = self._options.chrome_flags
59085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Set CHROME_HEADLESS. It enables crash reporter on posix.
59095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.environ['CHROME_HEADLESS'] = '1'
59105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.environ['EXTRA_CHROME_FLAGS'] = chrome_flags
59115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    test_names = self._ExpandTestNames(self._args)
59125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
59135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Shard, if requested (--shard).
59145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.shard:
59155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      matched = re.match('(\d+)/(\d+)', self._options.shard)
59165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not matched:
59175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print >>sys.stderr, 'Invalid sharding params: %s' % self._options.shard
59185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys.exit(1)
59195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shard_index = int(matched.group(1)) - 1
59205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      num_shards = int(matched.group(2))
59215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if shard_index < 0 or shard_index >= num_shards:
59225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print >>sys.stderr, 'Invalid sharding params: %s' % self._options.shard
59235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys.exit(1)
59245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      test_names = pyauto_utils.Shard(test_names, shard_index, num_shards)
59255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
59265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    test_names *= self._options.repeat
59275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.debug("Loading %d tests from %s", len(test_names), test_names)
59285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.list_tests:  # List tests and exit
59295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for name in test_names:
59305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print name
59315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sys.exit(0)
59325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pyauto_suite = PyUITestSuite(suite_args)
59335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    loaded_tests = unittest.defaultTestLoader.loadTestsFromNames(test_names)
59345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pyauto_suite.addTests(loaded_tests)
59355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    verbosity = 1
59365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.verbose:
59375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      verbosity = 2
59385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = PyAutoTextTestRunner(verbosity=verbosity).run(pyauto_suite)
59395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    del loaded_tests  # Need to destroy test cases before the suite
59405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    del pyauto_suite
59415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    successful = result.wasSuccessful()
59425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not successful:
59435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pyauto_tests_file = os.path.join(self.TestsDir(), self._tests_filename)
59445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print >>sys.stderr, 'Tests can be disabled by editing %s. ' \
59455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          'Ref: %s' % (pyauto_tests_file, _PYAUTO_DOC_URL)
59465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.exit(not successful)
59475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
59485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
59495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
59505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Main()
5951