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.
9 from telemetry
.core
import browser_finder
10 from telemetry
.core
import exceptions
11 from telemetry
.core
import extension_to_load
12 from telemetry
.core
import util
13 from telemetry
.core
.backends
.chrome
import cros_interface
14 from telemetry
.unittest
import options_for_unittests
16 class CrOSAutoTest(unittest
.TestCase
):
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',
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()
39 extension_path
= os
.path
.join(os
.path
.dirname(__file__
), 'autotest_ext')
40 self
._load
_extension
= extension_to_load
.ExtensionToLoad(
42 browser_type
=options
.browser_type
,
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
)
54 def _GetAutotestExtension(self
, browser
):
55 """Returns the autotest extension instance"""
56 extension
= browser
.extensions
[self
._load
_extension
]
57 self
.assertTrue(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;
71 lambda: extension
.EvaluateJavaScript('window.__login_status'), 10)
73 def testCryptohomeMounted(self
):
74 """Verifies cryptohome mount status for regular and guest user and when
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
)
84 self
.assertEquals(chronos_fs
, 'guestfs')
86 home
, _
= self
._cri
.RunCmdOnDevice(['/usr/sbin/cryptohome-path',
87 'user', self
._username
])
88 self
.assertEquals(self
._cri
.FilesystemMountedAt(home
.rstrip()),
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')
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
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
)
160 extension
.ExecuteJavaScript('chrome.autotestPrivate.logout();')
161 except (exceptions
.BrowserConnectionGoneException
,
162 exceptions
.BrowserGoneException
):
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
):
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;
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('-'))
208 # Map from other countries to a localized country
209 if lang
== 'es' and region
== 'es':
212 if region
in ('hk', 'mo'):
216 if region
in ('au', 'ca', 'nz', 'za'):
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
,
244 region
.language_code
)
245 if not languageFound
:
246 fallback
= self
._ResolveLanguage
(region
.language_code
)
247 self
.assertTrue(fallback
and
248 self
._OobeHasOption
(browser
,
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
271 class Enum(frozenset):
272 def __getattr__(self
, name
):
277 KeyboardMechanicalLayout
= Enum(['ANSI', 'ISO', 'JIS', 'ABNT2'])
278 _KML
= KeyboardMechanicalLayout
280 Region('au', 'xkb:us::eng', 'Australia/Sydney', 'en-AU', _KML
.ANSI
,
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
,
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
,
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
,
308 Region('nl', 'xkb:us:intl:eng', 'Europe/Amsterdam', 'nl', _KML
.ANSI
,
310 Region('nordic', 'xkb:se::swe', 'Europe/Stockholm', 'en-US', _KML
.ISO
,
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 '
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
,
322 Region('us', 'xkb:us::eng', 'America/Los_Angeles', 'en-US', _KML
.ANSI
,