Update CrOS OOBE throbber to MD throbber; delete old asset
[chromium-blink-merge.git] / chrome / test / telemetry / chromeos / login_unittest.py
blobcbd74b4af502a39dfb2655b0815e5224bbcbbf62
1 # Copyright (c) 2012 The Chromium 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 import json
5 import logging
6 import os
7 import unittest
9 from telemetry.core.backends.chrome import cros_interface
10 from telemetry.core import exceptions
11 from telemetry.core import util
12 from telemetry.internal.browser import extension_to_load
13 from telemetry.internal.browser import browser_finder
14 from telemetry.unittest import options_for_unittests
16 class CrOSAutoTest(unittest.TestCase):
17 def setUp(self):
18 options = options_for_unittests.GetCopy()
19 self._cri = cros_interface.CrOSInterface(options.cros_remote,
20 options.cros_ssh_identity)
21 self._is_guest = options.browser_type == 'cros-chrome-guest'
22 self._username = '' if self._is_guest else options.browser_options.username
23 self._password = options.browser_options.password
25 def _IsCryptohomeMounted(self):
26 """Returns True if cryptohome is mounted"""
27 cryptohomeJSON, _ = self._cri.RunCmdOnDevice(['/usr/sbin/cryptohome',
28 '--action=status'])
29 cryptohomeStatus = json.loads(cryptohomeJSON)
30 return (cryptohomeStatus['mounts'] and
31 cryptohomeStatus['mounts'][0]['mounted'])
33 def _CreateBrowser(self, autotest_ext=False, auto_login=True):
34 """Finds and creates a browser for tests. if autotest_ext is True,
35 also loads the autotest extension"""
36 options = options_for_unittests.GetCopy()
38 if autotest_ext:
39 extension_path = os.path.join(os.path.dirname(__file__), 'autotest_ext')
40 self._load_extension = extension_to_load.ExtensionToLoad(
41 path=extension_path,
42 browser_type=options.browser_type,
43 is_component=True)
44 options.extensions_to_load = [self._load_extension]
46 browser_to_create = browser_finder.FindBrowser(options)
47 self.assertTrue(browser_to_create)
48 options.browser_options.create_browser_with_oobe = True
49 options.browser_options.auto_login = auto_login
50 b = browser_to_create.Create(options)
51 b.Start()
52 return b
54 def _GetAutotestExtension(self, browser):
55 """Returns the autotest extension instance"""
56 extension = browser.extensions[self._load_extension]
57 self.assertTrue(extension)
58 return extension
60 def _GetLoginStatus(self, browser):
61 extension = self._GetAutotestExtension(browser)
62 self.assertTrue(extension.EvaluateJavaScript(
63 "typeof('chrome.autotestPrivate') != 'undefined'"))
64 extension.ExecuteJavaScript('''
65 window.__login_status = null;
66 chrome.autotestPrivate.loginStatus(function(s) {
67 window.__login_status = s;
68 });
69 ''')
70 return util.WaitFor(
71 lambda: extension.EvaluateJavaScript('window.__login_status'), 10)
73 def testCryptohomeMounted(self):
74 """Verifies cryptohome mount status for regular and guest user and when
75 logged out"""
76 with self._CreateBrowser() as b:
77 self.assertEquals(1, len(b.tabs))
78 self.assertTrue(b.tabs[0].url)
79 self.assertTrue(self._IsCryptohomeMounted())
81 chronos_fs = self._cri.FilesystemMountedAt('/home/chronos/user')
82 self.assertTrue(chronos_fs)
83 if self._is_guest:
84 self.assertEquals(chronos_fs, 'guestfs')
85 else:
86 home, _ = self._cri.RunCmdOnDevice(['/usr/sbin/cryptohome-path',
87 'user', self._username])
88 self.assertEquals(self._cri.FilesystemMountedAt(home.rstrip()),
89 chronos_fs)
91 self.assertFalse(self._IsCryptohomeMounted())
92 self.assertEquals(self._cri.FilesystemMountedAt('/home/chronos/user'),
93 '/dev/mapper/encstateful')
95 def testLoginStatus(self):
96 """Tests autotestPrivate.loginStatus"""
97 with self._CreateBrowser(autotest_ext=True) as b:
98 login_status = self._GetLoginStatus(b)
99 self.assertEquals(type(login_status), dict)
101 self.assertEquals(not self._is_guest, login_status['isRegularUser'])
102 self.assertEquals(self._is_guest, login_status['isGuest'])
103 self.assertEquals(login_status['email'], self._username)
104 self.assertFalse(login_status['isScreenLocked'])
106 def _IsScreenLocked(self, browser):
107 return self._GetLoginStatus(browser)['isScreenLocked']
109 def _LockScreen(self, browser):
110 self.assertFalse(self._IsScreenLocked(browser))
112 extension = self._GetAutotestExtension(browser)
113 self.assertTrue(extension.EvaluateJavaScript(
114 "typeof chrome.autotestPrivate.lockScreen == 'function'"))
115 logging.info('Locking screen')
116 extension.ExecuteJavaScript('chrome.autotestPrivate.lockScreen();')
118 logging.info('Waiting for the lock screen')
119 def ScreenLocked():
120 return (browser.oobe and
121 browser.oobe.EvaluateJavaScript("typeof Oobe == 'function'") and
122 browser.oobe.EvaluateJavaScript(
123 "typeof Oobe.authenticateForTesting == 'function'"))
124 util.WaitFor(ScreenLocked, 10)
125 self.assertTrue(self._IsScreenLocked(browser))
127 def _AttemptUnlockBadPassword(self, browser):
128 logging.info('Trying a bad password')
129 def ErrorBubbleVisible():
130 return not browser.oobe.EvaluateJavaScript('''
131 document.getElementById('bubble').hidden
132 ''')
133 self.assertFalse(ErrorBubbleVisible())
134 browser.oobe.ExecuteJavaScript('''
135 Oobe.authenticateForTesting('%s', 'bad');
136 ''' % self._username)
137 util.WaitFor(ErrorBubbleVisible, 10)
138 self.assertTrue(self._IsScreenLocked(browser))
140 def _UnlockScreen(self, browser):
141 logging.info('Unlocking')
142 browser.oobe.ExecuteJavaScript('''
143 Oobe.authenticateForTesting('%s', '%s');
144 ''' % (self._username, self._password))
145 util.WaitFor(lambda: not browser.oobe, 10)
146 self.assertFalse(self._IsScreenLocked(browser))
148 def testScreenLock(self):
149 """Tests autotestPrivate.screenLock"""
150 with self._CreateBrowser(autotest_ext=True) as browser:
151 self._LockScreen(browser)
152 self._AttemptUnlockBadPassword(browser)
153 self._UnlockScreen(browser)
155 def testLogout(self):
156 """Tests autotestPrivate.logout"""
157 with self._CreateBrowser(autotest_ext=True) as b:
158 extension = self._GetAutotestExtension(b)
159 try:
160 extension.ExecuteJavaScript('chrome.autotestPrivate.logout();')
161 except (exceptions.BrowserConnectionGoneException,
162 exceptions.BrowserGoneException):
163 pass
164 util.WaitFor(lambda: not self._IsCryptohomeMounted(), 20)
166 def _SwitchRegion(self, region):
167 self._cri.RunCmdOnDevice(['stop', 'ui'])
169 # Change VPD (requires RW-enabled firmware).
170 # To save time, region and initial_timezone are not set.
171 vpd = {'initial_locale': region.language_code,
172 'keyboard_layout': region.keyboard}
174 for (key, value) in vpd.items():
175 self._cri.RunCmdOnDevice(['vpd', '-s', '"%s"="%s"' % (key, value)])
177 # Remove cached files to clear initial locale info and force regeneration.
178 self._cri.RunCmdOnDevice(['rm', '/home/chronos/Local\ State'])
179 self._cri.RunCmdOnDevice(['rm', '/home/chronos/.oobe_completed'])
180 self._cri.RunCmdOnDevice(['dump_vpd_log', '--force'])
182 self._cri.RunCmdOnDevice(['start', 'ui'])
184 def _OobeHasOption(self, browser, selectId, value):
185 hasOptionJs = '''
186 // Check that the option is present, and selected if it is the default.
187 (function hasOption(selectId, value, isDefault) {
188 var options = document.getElementById(selectId).options;
189 for (var i = 0; i < options.length; i++) {
190 if (options[i].value == value) {
191 // The option is present. Make sure it's selected if necessary.
192 return !isDefault || options.selectedIndex == i;
195 return false;
196 })("%s", "%s", %s);
198 return browser.oobe.EvaluateJavaScript(
199 hasOptionJs % (selectId, value, 'true'))
201 def _ResolveLanguage(self, locale):
202 # If the locale matches a language but not the country, fall back to
203 # an existing locale. See ui/base/l10n/l10n_util.cc.
204 lang, _, region = map(str.lower, locale.partition('-'))
205 if not region:
206 return ""
208 # Map from other countries to a localized country
209 if lang == 'es' and region == 'es':
210 return 'es-419'
211 if lang == 'zh':
212 if region in ('hk', 'mo'):
213 return 'zh-TW'
214 return 'zh-CN'
215 if lang == 'en':
216 if region in ('au', 'ca', 'nz', 'za'):
217 return 'en-GB'
218 return 'en-US'
220 # No mapping found
221 return ""
223 def testOobeLocalization(self):
224 """Tests different region configurations at OOBE"""
225 # Save the original device localization settings.
226 # To save time, only read initial_locale and keyboard_layout.
227 initial_region = self.Region('', '', '', '', '')
228 initial_region.language_code, _ = self._cri.RunCmdOnDevice(
229 ['vpd', '-g', 'initial_locale'])
230 initial_region.keyboard, _ = self._cri.RunCmdOnDevice(
231 ['vpd', '-g', 'keyboard_layout'])
233 for region in self.REGIONS_LIST:
234 self._SwitchRegion(region)
235 with self._CreateBrowser(auto_login=False) as browser:
236 # Ensure the dropdown lists have been created.
237 util.WaitFor(lambda: browser.oobe.EvaluateJavaScript(
238 'document.getElementById("language-select") != null'),
241 # Find the language, or an acceptable fallback value.
242 languageFound = self._OobeHasOption(browser,
243 'language-select',
244 region.language_code)
245 if not languageFound:
246 fallback = self._ResolveLanguage(region.language_code)
247 self.assertTrue(fallback and
248 self._OobeHasOption(browser,
249 'language-select',
250 fallback))
252 # Find the keyboard layout.
253 self.assertTrue(self._OobeHasOption(
254 browser, 'keyboard-select', region.keyboard))
256 # Test is finished. Restore original region settings.
257 self._SwitchRegion(initial_region)
259 # The Region class and region list will be available in regions.py.
260 class Region(object):
261 def __init__(self, region_code, keyboard, time_zone, language_code,
262 keyboard_mechanical_layout, description=None, notes=None):
263 self.region_code = region_code
264 self.keyboard = keyboard
265 self.time_zone = time_zone
266 self.language_code = language_code
267 self.keyboard_mechanical_layout = keyboard_mechanical_layout
268 self.description = description or region_code
269 self.notes = notes
271 class Enum(frozenset):
272 def __getattr__(self, name):
273 if name in self:
274 return name
275 raise AttributeError
277 KeyboardMechanicalLayout = Enum(['ANSI', 'ISO', 'JIS', 'ABNT2'])
278 _KML = KeyboardMechanicalLayout
279 REGIONS_LIST = [
280 Region('au', 'xkb:us::eng', 'Australia/Sydney', 'en-AU', _KML.ANSI,
281 'Australia'),
282 Region('ca.ansi', 'xkb:us::eng', 'America/Toronto', 'en-CA', _KML.ANSI,
283 'Canada (US keyboard)',
284 'Canada with US (ANSI) keyboard; see http://goto/cros-canada'),
285 Region('ca.fr', 'xkb:ca::fra', 'America/Toronto', 'fr-CA', _KML.ISO,
286 'Canada (French keyboard)',
287 ('Canadian French (ISO) keyboard. The most common configuration for '
288 'Canadian French SKUs. See http://goto/cros-canada')),
289 Region('ca.hybrid', 'xkb:ca:eng:eng', 'America/Toronto', 'en-CA', _KML.ISO,
290 'Canada (hybrid)',
291 ('Canada with hybrid xkb:ca:eng:eng + xkb:ca::fra keyboard (ISO), '
292 'defaulting to English language and keyboard. Used only if there '
293 'needs to be a single SKU for all of Canada. See '
294 'http://goto/cros-canada')),
295 Region('ca.multix', 'xkb:ca:multix:fra', 'America/Toronto', 'fr-CA',
296 _KML.ISO, 'Canada (multilingual)',
297 ("Canadian Multilingual keyboard; you probably don't want this. See "
298 "http://goto/cros-canada")),
299 Region('de', 'xkb:de::ger', 'Europe/Berlin', 'de', _KML.ISO, 'Germany'),
300 Region('fi', 'xkb:fi::fin', 'Europe/Helsinki', 'fi', _KML.ISO, 'Finland'),
301 Region('fr', 'xkb:fr::fra', 'Europe/Paris', 'fr', _KML.ISO, 'France'),
302 Region('gb', 'xkb:gb:extd:eng', 'Europe/London', 'en-GB', _KML.ISO, 'UK'),
303 Region('ie', 'xkb:gb:extd:eng', 'Europe/Dublin', 'en-GB', _KML.ISO,
304 'Ireland'),
305 Region('in', 'xkb:us::eng', 'Asia/Calcutta', 'en-US', _KML.ANSI, 'India'),
306 Region('my', 'xkb:us::eng', 'Asia/Kuala_Lumpur', 'ms', _KML.ANSI,
307 'Malaysia'),
308 Region('nl', 'xkb:us:intl:eng', 'Europe/Amsterdam', 'nl', _KML.ANSI,
309 'Netherlands'),
310 Region('nordic', 'xkb:se::swe', 'Europe/Stockholm', 'en-US', _KML.ISO,
311 'Nordics',
312 ('Unified SKU for Sweden, Norway, and Denmark. This defaults '
313 'to Swedish keyboard layout, but starts with US English language '
314 'for neutrality. Use if there is a single combined SKU for Nordic '
315 'countries.')),
316 Region('se', 'xkb:se::swe', 'Europe/Stockholm', 'sv', _KML.ISO, 'Sweden',
317 ("Use this if there separate SKUs for Nordic countries (Sweden, "
318 "Norway, and Denmark), or the device is only shipping to Sweden. "
319 "If there is a single unified SKU, use 'nordic' instead.")),
320 Region('sg', 'xkb:us::eng', 'Asia/Singapore', 'en-GB', _KML.ANSI,
321 'Singapore'),
322 Region('us', 'xkb:us::eng', 'America/Los_Angeles', 'en-US', _KML.ANSI,
323 'United States'),