blob: 149f00f416cffd2c37f9a798b6ce8567e1412e6b [file] [log] [blame]
Dennis Jeffreydffc0bd2013-05-03 13:24:31 -07001# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Achuith Bhandarkarf3469ec2016-06-08 16:58:57 -07005import logging, os, re
Achuith Bhandarkara2df47b2013-10-09 21:23:15 -07006
Nicolas Boichat451e4662016-07-16 07:51:01 +08007from autotest_lib.client.common_lib.cros import arc_util
Don Garrett11b13972015-09-11 17:37:53 +00008from autotest_lib.client.cros import constants
Achuith Bhandarkar88a2bab2015-07-09 17:36:25 -07009from autotest_lib.client.bin import utils
Prathmesh Prabhuc3961df2015-07-21 10:44:54 -070010from telemetry.core import cros_interface, exceptions, util
Achuith Bhandarkarb058a8f2015-07-02 01:29:05 -070011from telemetry.internal.browser import browser_finder, browser_options
12from telemetry.internal.browser import extension_to_load
Achuith Bhandarkar704134d2015-03-05 17:31:57 -080013
14Error = exceptions.Error
Dennis Jeffreydffc0bd2013-05-03 13:24:31 -070015
16
Victor Hsieh43651ac2016-04-20 12:52:21 -070017# Cached result of whether ARC is available on current device.
18_arc_available = None
19
20
Nicolas Norvez56f9b232016-06-23 17:58:59 -070021def is_arc_available():
Victor Hsieh000240b2016-04-11 16:04:31 -070022 """Returns true if ARC is available on current device."""
Victor Hsieh43651ac2016-04-20 12:52:21 -070023 global _arc_available
24 if _arc_available is not None:
25 return _arc_available
26
27 def _check_lsb_release():
28 lsb_release = '/etc/lsb-release'
29 if not os.path.exists(lsb_release):
30 return False
31 with open(lsb_release) as f:
32 for line in f:
33 if line.startswith('CHROMEOS_ARC_VERSION='):
34 return True
35 return False
36
37 _arc_available = _check_lsb_release()
38 return _arc_available
39
40
Achuith Bhandarkarf3469ec2016-06-08 16:58:57 -070041def NormalizeEmail(username):
42 """Remove dots from username. Add @gmail.com if necessary.
43
44 TODO(achuith): Get rid of this when crbug.com/358427 is fixed.
45
46 @param username: username/email to be scrubbed.
47 """
48 parts = re.split('@', username)
49 parts[0] = re.sub('\.', '', parts[0])
50
51 if len(parts) == 1:
52 parts.append('gmail.com')
53 return '@'.join(parts)
54
55
Achuith Bhandarkared498932013-07-16 17:01:40 -070056class Chrome(object):
Ricky Liang2bfa5642016-11-09 10:18:37 +080057 """Wrapper for creating a telemetry browser instance with extensions.
58
59 The recommended way to use this class is to create the instance using the
60 with statement:
61
62 >>> with chrome.Chrome(...) as cr:
63 >>> # Do whatever you need with cr.
64 >>> pass
65
66 This will make sure all the clean-up functions are called. If you really
67 need to use this class without the with statement, make sure to call the
68 close() method once you're done with the Chrome instance.
69 """
Achuith Bhandarkar86c46812013-07-15 17:13:39 -070070
71
Achuith Bhandarkared498932013-07-16 17:01:40 -070072 BROWSER_TYPE_LOGIN = 'system'
73 BROWSER_TYPE_GUEST = 'system-guest'
Achuith Bhandarkar86c46812013-07-15 17:13:39 -070074
75
Achuith Bhandarkarb0e99072013-11-18 16:15:03 -080076 def __init__(self, logged_in=True, extension_paths=[], autotest_ext=False,
Achuith Bhandarkar4a46bb82016-10-10 12:23:28 -070077 num_tries=3, extra_browser_args=None,
Achuith Bhandarkar882a8ab2014-08-26 15:51:20 -070078 clear_enterprise_policy=True, dont_override_profile=False,
Achuith Bhandarkara2bceaf2014-11-14 12:10:16 -080079 disable_gaia_services=True, disable_default_apps = True,
80 auto_login=True, gaia_login=False,
Victor Hsieh000240b2016-04-11 16:04:31 -070081 username=None, password=None, gaia_id=None,
Achuith Bhandarkar08f9a592017-01-20 17:14:02 -080082 arc_mode=None, disable_arc_opt_in=True,
83 init_network_controller=True):
Dean Liaob12e2ee2013-11-19 16:49:12 +080084 """
Achuith Bhandarkar944405a2013-11-21 14:47:48 -080085 Constructor of telemetry wrapper.
86
87 @param logged_in: Regular user (True) or guest user (False).
88 @param extension_paths: path of unpacked extension to install.
89 @param autotest_ext: Load a component extension with privileges to
90 invoke chrome.autotestPrivate.
Achuith Bhandarkarb7ef5e52014-03-20 14:18:45 -070091 @param num_tries: Number of attempts to log in.
Dean Liaob12e2ee2013-11-19 16:49:12 +080092 @param extra_browser_args: Additional argument(s) to pass to the
Achuith Bhandarkar3875e0c2014-03-20 14:17:31 -070093 browser. It can be a string or a list.
Achuith Bhandarkar5d6c26c2014-04-25 11:19:38 -070094 @param clear_enterprise_policy: Clear enterprise policy before
95 logging in.
Achuith Bhandarkar882a8ab2014-08-26 15:51:20 -070096 @param dont_override_profile: Don't delete cryptohome before login.
97 Telemetry will output a warning with this
98 option.
Achuith Bhandarkar3c654f32014-09-29 06:33:35 -070099 @param disable_gaia_services: For enterprise autotests, this option may
100 be used to enable policy fetch.
Achuith Bhandarkara2bceaf2014-11-14 12:10:16 -0800101 @param disable_default_apps: For tests that exercise default apps.
Achuith Bhandarkar1cce9dc2014-02-05 14:23:34 -0800102 @param auto_login: Does not login automatically if this is False.
Achuith Bhandarkar3875e0c2014-03-20 14:17:31 -0700103 Useful if you need to examine oobe.
104 @param gaia_login: Logs in to real gaia.
Achuith Bhandarkar1cce9dc2014-02-05 14:23:34 -0800105 @param username: Log in using this username instead of the default.
Alexander Alekseevd9682862015-10-01 22:42:49 -0700106 @param password: Log in using this password instead of the default.
107 @param gaia_id: Log in using this gaia_id instead of the default.
Victor Hsieh43651ac2016-04-20 12:52:21 -0700108 @param arc_mode: How ARC instance should be started. Default is to not
109 start.
F#md6d56ba2016-06-10 14:40:52 -0700110 @param disable_arc_opt_in: For opt in flow autotest. This option is used
111 to disable the arc opt in flow.
Dean Liaob12e2ee2013-11-19 16:49:12 +0800112 """
Achuith Bhandarkara2df47b2013-10-09 21:23:15 -0700113 self._autotest_ext_path = None
114 if autotest_ext:
115 self._autotest_ext_path = os.path.join(os.path.dirname(__file__),
116 'autotest_private_ext')
117 extension_paths.append(self._autotest_ext_path)
118
Achuith Bhandarkar7fb57f72013-08-29 15:29:06 -0700119 finder_options = browser_options.BrowserFinderOptions()
Nicolas Norvez56f9b232016-06-23 17:58:59 -0700120 if is_arc_available() and arc_util.should_start_arc(arc_mode):
F#md6d56ba2016-06-10 14:40:52 -0700121 if disable_arc_opt_in:
122 finder_options.browser_options.AppendExtraBrowserArgs(
123 arc_util.get_extra_chrome_flags())
Victor Hsieh43651ac2016-04-20 12:52:21 -0700124 logged_in = True
125
Achuith Bhandarkared498932013-07-16 17:01:40 -0700126 self._browser_type = (self.BROWSER_TYPE_LOGIN
127 if logged_in else self.BROWSER_TYPE_GUEST)
Achuith Bhandarkarf130c402013-09-11 14:39:22 -0700128 finder_options.browser_type = self.browser_type
Dean Liaob12e2ee2013-11-19 16:49:12 +0800129 if extra_browser_args:
130 finder_options.browser_options.AppendExtraBrowserArgs(
131 extra_browser_args)
Achuith Bhandarkarf130c402013-09-11 14:39:22 -0700132
Achuith Bhandarkar3e5051d2013-10-15 15:20:12 -0700133 # finder options must be set before parse_args(), browser options must
134 # be set before Create().
Todd Brocheb6f4812014-04-29 16:04:28 -0700135 # TODO(crbug.com/360890) Below MUST be '2' so that it doesn't inhibit
136 # autotest debug logs
137 finder_options.verbosity = 2
Achuith Bhandarkardafc9a52013-09-24 15:26:33 +0200138 finder_options.CreateParser().parse_args(args=[])
Achuith Bhandarkara2df47b2013-10-09 21:23:15 -0700139 b_options = finder_options.browser_options
140 b_options.disable_component_extensions_with_background_pages = False
141 b_options.create_browser_with_oobe = True
Achuith Bhandarkar5d6c26c2014-04-25 11:19:38 -0700142 b_options.clear_enterprise_policy = clear_enterprise_policy
Achuith Bhandarkar882a8ab2014-08-26 15:51:20 -0700143 b_options.dont_override_profile = dont_override_profile
Achuith Bhandarkar3c654f32014-09-29 06:33:35 -0700144 b_options.disable_gaia_services = disable_gaia_services
Achuith Bhandarkara2bceaf2014-11-14 12:10:16 -0800145 b_options.disable_default_apps = disable_default_apps
146 b_options.disable_component_extensions_with_background_pages = disable_default_apps
Achuith Bhandarkar1cce9dc2014-02-05 14:23:34 -0800147
148 b_options.auto_login = auto_login
Achuith Bhandarkar3875e0c2014-03-20 14:17:31 -0700149 b_options.gaia_login = gaia_login
F#md6d56ba2016-06-10 14:40:52 -0700150
Nicolas Norvez56f9b232016-06-23 17:58:59 -0700151 if is_arc_available() and not disable_arc_opt_in:
F#md6d56ba2016-06-10 14:40:52 -0700152 arc_util.set_browser_options_for_opt_in(b_options)
153
Achuith Bhandarkar1cce9dc2014-02-05 14:23:34 -0800154 self.username = b_options.username if username is None else username
155 self.password = b_options.password if password is None else password
Achuith Bhandarkarf3469ec2016-06-08 16:58:57 -0700156 self.username = NormalizeEmail(self.username)
Achuith Bhandarkar1cce9dc2014-02-05 14:23:34 -0800157 b_options.username = self.username
158 b_options.password = self.password
Achuith Bhandarkar6f4accc2016-08-23 14:03:44 -0700159 self.gaia_id = b_options.gaia_id if gaia_id is None else gaia_id
160 b_options.gaia_id = self.gaia_id
Achuith Bhandarkara2df47b2013-10-09 21:23:15 -0700161
Shuhei Takahashi8462b882016-05-31 17:27:32 +0900162 self.arc_mode = arc_mode
163
Achuith Bhandarkar531a62a2016-04-13 11:09:43 -0700164 if logged_in:
Achuith Bhandarkar6f4accc2016-08-23 14:03:44 -0700165 extensions_to_load = b_options.extensions_to_load
166 for path in extension_paths:
167 extension = extension_to_load.ExtensionToLoad(
Achuith Bhandarkar4a46bb82016-10-10 12:23:28 -0700168 path, self.browser_type)
Achuith Bhandarkar6f4accc2016-08-23 14:03:44 -0700169 extensions_to_load.append(extension)
170 self._extensions_to_load = extensions_to_load
Achuith Bhandarkar531a62a2016-04-13 11:09:43 -0700171
David James54a830e2015-05-06 17:21:47 -0700172 # Turn on collection of Chrome coredumps via creation of a magic file.
173 # (Without this, Chrome coredumps are trashed.)
Don Garrett11b13972015-09-11 17:37:53 +0000174 open(constants.CHROME_CORE_MAGIC_FILE, 'w').close()
David James54a830e2015-05-06 17:21:47 -0700175
Achuith Bhandarkarb0e99072013-11-18 16:15:03 -0800176 for i in range(num_tries):
177 try:
178 browser_to_create = browser_finder.FindBrowser(finder_options)
Achuith Bhandarkara2bceaf2014-11-14 12:10:16 -0800179 self._browser = browser_to_create.Create(finder_options)
Nicolas Norvez56f9b232016-06-23 17:58:59 -0700180 if is_arc_available():
khmele0434292016-11-10 13:27:57 -0800181 if disable_arc_opt_in:
182 if arc_util.should_start_arc(arc_mode):
183 arc_util.enable_arc_setting(self.browser)
184 else:
F#md6d56ba2016-06-10 14:40:52 -0700185 arc_util.opt_in(self.browser)
Ricky Zhoucf350ee2016-06-13 15:47:33 -0700186 arc_util.post_processing_after_browser(self)
Achuith Bhandarkarb0e99072013-11-18 16:15:03 -0800187 break
khmela7cf9dd2016-09-20 10:50:23 -0700188 except exceptions.LoginException as e:
Achuith Bhandarkarf800edf2013-12-06 13:37:52 -0800189 logging.error('Timed out logging in, tries=%d, error=%s',
190 i, repr(e))
Achuith Bhandarkarb0e99072013-11-18 16:15:03 -0800191 if i == num_tries-1:
192 raise
Achuith Bhandarkar08f9a592017-01-20 17:14:02 -0800193 if init_network_controller:
194 self._browser.platform.network_controller.InitializeIfNeeded()
Achuith Bhandarkared498932013-07-16 17:01:40 -0700195
196 def __enter__(self):
197 return self
198
199
200 def __exit__(self, *args):
Derek Basehore41acbf82014-07-11 18:34:30 -0700201 self.close()
Achuith Bhandarkared498932013-07-16 17:01:40 -0700202
203
204 @property
205 def browser(self):
206 """Returns a telemetry browser instance."""
207 return self._browser
208
209
210 def get_extension(self, extension_path):
211 """Fetches a telemetry extension instance given the extension path."""
212 for ext in self._extensions_to_load:
213 if extension_path == ext.path:
214 return self.browser.extensions[ext]
215 return None
216
217
218 @property
Achuith Bhandarkara2df47b2013-10-09 21:23:15 -0700219 def autotest_ext(self):
220 """Returns the autotest extension."""
221 return self.get_extension(self._autotest_ext_path)
222
223
224 @property
225 def login_status(self):
226 """Returns login status."""
227 ext = self.autotest_ext
228 if not ext:
229 return None
230
231 ext.ExecuteJavaScript('''
232 window.__login_status = null;
233 chrome.autotestPrivate.loginStatus(function(s) {
234 window.__login_status = s;
235 });
236 ''')
237 return ext.EvaluateJavaScript('window.__login_status')
238
239
Victor Hsiehfc3417e2016-03-25 16:49:59 -0700240 def get_visible_notifications(self):
241 """Returns an array of visible notifications of Chrome.
242
243 For specific type of each notification, please refer to Chromium's
244 chrome/common/extensions/api/autotest_private.idl.
245 """
246 ext = self.autotest_ext
247 if not ext:
248 return None
249
250 ext.ExecuteJavaScript('''
251 window.__items = null;
252 chrome.autotestPrivate.getVisibleNotifications(function(items) {
253 window.__items = items;
254 });
255 ''')
256 if ext.EvaluateJavaScript('window.__items') is None:
257 return None
258 return ext.EvaluateJavaScript('window.__items')
259
260
Achuith Bhandarkara2df47b2013-10-09 21:23:15 -0700261 @property
Achuith Bhandarkared498932013-07-16 17:01:40 -0700262 def browser_type(self):
263 """Returns the browser_type."""
264 return self._browser_type
Achuith Bhandarkar49c72d92013-07-25 11:10:10 -0700265
266
Achuith Bhandarkar16ee9772015-01-23 17:18:18 -0800267 @staticmethod
268 def did_browser_crash(func):
Achuith Bhandarkar7fb57f72013-08-29 15:29:06 -0700269 """Runs func, returns True if the browser crashed, False otherwise.
270
271 @param func: function to run.
272
273 """
Achuith Bhandarkar5abf60b2013-08-01 12:35:53 -0700274 try:
275 func()
khmela7cf9dd2016-09-20 10:50:23 -0700276 except Error:
Achuith Bhandarkar5abf60b2013-08-01 12:35:53 -0700277 return True
278 return False
Derek Basehore41acbf82014-07-11 18:34:30 -0700279
280
Achuith Bhandarkar88a2bab2015-07-09 17:36:25 -0700281 @staticmethod
282 def wait_for_browser_restart(func):
283 """Runs func, and waits for a browser restart.
284
285 @param func: function to run.
286
287 """
288 _cri = cros_interface.CrOSInterface()
289 pid = _cri.GetChromePid()
290 Chrome.did_browser_crash(func)
291 utils.poll_for_condition(lambda: pid != _cri.GetChromePid(), timeout=60)
292
293
Achuith Bhandarkar16ee9772015-01-23 17:18:18 -0800294 def wait_for_browser_to_come_up(self):
295 """Waits for the browser to come up. This should only be called after a
296 browser crash.
297 """
298 def _BrowserReady(cr):
299 tabs = [] # Wrapper for pass by reference.
300 if self.did_browser_crash(
301 lambda: tabs.append(cr.browser.tabs.New())):
302 return False
303 try:
304 tabs[0].Close()
Achuith Bhandarkarfab82d12015-02-26 11:05:35 -0800305 except:
Achuith Bhandarkar16ee9772015-01-23 17:18:18 -0800306 # crbug.com/350941
307 logging.error('Timed out closing tab')
308 return True
309 util.WaitFor(lambda: _BrowserReady(self), timeout=10)
310
311
Derek Basehore41acbf82014-07-11 18:34:30 -0700312 def close(self):
Achuith Bhandarkar1cc41572016-09-30 09:47:46 -0700313 """Closes the browser.
314 """
khmela7cf9dd2016-09-20 10:50:23 -0700315 try:
Nicolas Norvez56f9b232016-06-23 17:58:59 -0700316 if is_arc_available():
Shuhei Takahashi8462b882016-05-31 17:27:32 +0900317 arc_util.pre_processing_before_close(self)
Hidehiko Abe202ed322016-04-14 15:08:43 +0900318 finally:
Ricky Liang2bfa5642016-11-09 10:18:37 +0800319 # Calling platform.StopAllLocalServers() to tear down the telemetry
320 # server processes such as the one started by
321 # platform.SetHTTPServerDirectories(). Not calling this function
322 # will leak the process and may affect test results.
323 # (crbug.com/663387)
324 self._browser.platform.StopAllLocalServers()
Hidehiko Abe202ed322016-04-14 15:08:43 +0900325 self._browser.Close()
John Budorick0038e102016-11-08 10:39:15 -0800326 self._browser.platform.network_controller.Close()