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