1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import json
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import logging
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import os
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import unittest
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)from telemetry.core import browser_finder
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)from telemetry.core import exceptions
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)from telemetry.core import extension_to_load
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)from telemetry.core import util
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)from telemetry.core.backends.chrome import cros_interface
14424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)from telemetry.unittest import options_for_unittests
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class CrOSAutoTest(unittest.TestCase):
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def setUp(self):
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    options = options_for_unittests.GetCopy()
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self._cri = cros_interface.CrOSInterface(options.cros_remote,
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             options.cros_ssh_identity)
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self._is_guest = options.browser_type == 'cros-chrome-guest'
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._username = '' if self._is_guest else options.browser_options.username
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._password = options.browser_options.password
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def _IsCryptohomeMounted(self):
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    """Returns True if cryptohome is mounted"""
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    cryptohomeJSON, _ = self._cri.RunCmdOnDevice(['/usr/sbin/cryptohome',
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 '--action=status'])
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    cryptohomeStatus = json.loads(cryptohomeJSON)
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return (cryptohomeStatus['mounts'] and
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            cryptohomeStatus['mounts'][0]['mounted'])
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def _CreateBrowser(self, autotest_ext=False, auto_login=True):
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Finds and creates a browser for tests. if autotest_ext is True,
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    also loads the autotest extension"""
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    options = options_for_unittests.GetCopy()
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if autotest_ext:
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      extension_path = os.path.join(os.path.dirname(__file__), 'autotest_ext')
40424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      self._load_extension = extension_to_load.ExtensionToLoad(
41424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          path=extension_path,
42424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          browser_type=options.browser_type,
43424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          is_component=True)
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      options.extensions_to_load = [self._load_extension]
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    browser_to_create = browser_finder.FindBrowser(options)
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.assertTrue(browser_to_create)
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    options.browser_options.create_browser_with_oobe = True
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    options.browser_options.auto_login = auto_login
50424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    b = browser_to_create.Create()
51424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    b.Start()
52424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return b
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def _GetAutotestExtension(self, browser):
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    """Returns the autotest extension instance"""
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    extension = browser.extensions[self._load_extension]
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.assertTrue(extension)
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return extension
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def _GetLoginStatus(self, browser):
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      extension = self._GetAutotestExtension(browser)
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      self.assertTrue(extension.EvaluateJavaScript(
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          "typeof('chrome.autotestPrivate') != 'undefined'"))
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      extension.ExecuteJavaScript('''
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        window.__login_status = null;
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        chrome.autotestPrivate.loginStatus(function(s) {
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          window.__login_status = s;
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        });
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ''')
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return util.WaitFor(
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          lambda: extension.EvaluateJavaScript('window.__login_status'), 10)
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def testCryptohomeMounted(self):
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    """Verifies cryptohome mount status for regular and guest user and when
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    logged out"""
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    with self._CreateBrowser() as b:
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self.assertEquals(1, len(b.tabs))
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self.assertTrue(b.tabs[0].url)
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self.assertTrue(self._IsCryptohomeMounted())
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      chronos_fs = self._cri.FilesystemMountedAt('/home/chronos/user')
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self.assertTrue(chronos_fs)
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if self._is_guest:
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        self.assertEquals(chronos_fs, 'guestfs')
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      else:
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        home, _ = self._cri.RunCmdOnDevice(['/usr/sbin/cryptohome-path',
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            'user', self._username])
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        self.assertEquals(self._cri.FilesystemMountedAt(home.rstrip()),
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          chronos_fs)
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.assertFalse(self._IsCryptohomeMounted())
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.assertEquals(self._cri.FilesystemMountedAt('/home/chronos/user'),
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      '/dev/mapper/encstateful')
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def testLoginStatus(self):
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    """Tests autotestPrivate.loginStatus"""
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    with self._CreateBrowser(autotest_ext=True) as b:
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      login_status = self._GetLoginStatus(b)
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self.assertEquals(type(login_status), dict)
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self.assertEquals(not self._is_guest, login_status['isRegularUser'])
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self.assertEquals(self._is_guest, login_status['isGuest'])
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.assertEquals(login_status['email'], self._username)
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self.assertFalse(login_status['isScreenLocked'])
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def _IsScreenLocked(self, browser):
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return self._GetLoginStatus(browser)['isScreenLocked']
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def _LockScreen(self, browser):
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      self.assertFalse(self._IsScreenLocked(browser))
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      extension = self._GetAutotestExtension(browser)
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      self.assertTrue(extension.EvaluateJavaScript(
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          "typeof chrome.autotestPrivate.lockScreen == 'function'"))
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      logging.info('Locking screen')
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      extension.ExecuteJavaScript('chrome.autotestPrivate.lockScreen();')
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      logging.info('Waiting for the lock screen')
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      def ScreenLocked():
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return (browser.oobe and
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            browser.oobe.EvaluateJavaScript("typeof Oobe == 'function'") and
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            browser.oobe.EvaluateJavaScript(
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            "typeof Oobe.authenticateForTesting == 'function'"))
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      util.WaitFor(ScreenLocked, 10)
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      self.assertTrue(self._IsScreenLocked(browser))
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def _AttemptUnlockBadPassword(self, browser):
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      logging.info('Trying a bad password')
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      def ErrorBubbleVisible():
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return not browser.oobe.EvaluateJavaScript('''
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            document.getElementById('bubble').hidden
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        ''')
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      self.assertFalse(ErrorBubbleVisible())
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      browser.oobe.ExecuteJavaScript('''
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          Oobe.authenticateForTesting('%s', 'bad');
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ''' % self._username)
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      util.WaitFor(ErrorBubbleVisible, 10)
1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      self.assertTrue(self._IsScreenLocked(browser))
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def _UnlockScreen(self, browser):
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      logging.info('Unlocking')
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      browser.oobe.ExecuteJavaScript('''
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          Oobe.authenticateForTesting('%s', '%s');
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ''' % (self._username, self._password))
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      util.WaitFor(lambda: not browser.oobe, 10)
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      self.assertFalse(self._IsScreenLocked(browser))
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def testScreenLock(self):
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    """Tests autotestPrivate.screenLock"""
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    with self._CreateBrowser(autotest_ext=True) as browser:
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      self._LockScreen(browser)
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      self._AttemptUnlockBadPassword(browser)
1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      self._UnlockScreen(browser)
1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def testLogout(self):
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    """Tests autotestPrivate.logout"""
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    with self._CreateBrowser(autotest_ext=True) as b:
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      extension = self._GetAutotestExtension(b)
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      try:
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        extension.ExecuteJavaScript('chrome.autotestPrivate.logout();')
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      except (exceptions.BrowserConnectionGoneException,
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              exceptions.BrowserGoneException):
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        pass
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      util.WaitFor(lambda: not self._IsCryptohomeMounted(), 20)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def _SwitchRegion(self, region):
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._cri.RunCmdOnDevice(['stop', 'ui'])
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Change VPD (requires RW-enabled firmware).
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # To save time, region and initial_timezone are not set.
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    vpd = {'initial_locale': region.language_code,
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           'keyboard_layout': region.keyboard}
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (key, value) in vpd.items():
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self._cri.RunCmdOnDevice(['vpd', '-s', '"%s"="%s"' % (key, value)])
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Remove cached files to clear initial locale info and force regeneration.
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._cri.RunCmdOnDevice(['rm', '/home/chronos/Local\ State'])
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._cri.RunCmdOnDevice(['rm', '/home/chronos/.oobe_completed'])
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._cri.RunCmdOnDevice(['dump_vpd_log', '--force'])
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._cri.RunCmdOnDevice(['start', 'ui'])
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def _OobeHasOption(self, browser, selectId, value):
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    hasOptionJs = '''
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Check that the option is present, and selected if it is the default.
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (function hasOption(selectId, value, isDefault) {
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        var options = document.getElementById(selectId).options;
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for (var i = 0; i < options.length; i++) {
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          if (options[i].value == value) {
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            // The option is present. Make sure it's selected if necessary.
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            return !isDefault || options.selectedIndex == i;
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          }
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return false;
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      })("%s", "%s", %s);
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    '''
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return browser.oobe.EvaluateJavaScript(
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        hasOptionJs % (selectId, value, 'true'))
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def _ResolveLanguage(self, locale):
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # If the locale matches a language but not the country, fall back to
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # an existing locale. See ui/base/l10n/l10n_util.cc.
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    lang, _, region = map(str.lower, locale.partition('-'))
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not region:
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return ""
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Map from other countries to a localized country
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if lang == 'es' and region == 'es':
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return 'es-419'
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if lang == 'zh':
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if region in ('hk', 'mo'):
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return 'zh-TW'
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return 'zh-CN'
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if lang == 'en':
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if region in ('au', 'ca', 'nz', 'za'):
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return 'en-GB'
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return 'en-US'
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # No mapping found
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return ""
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def testOobeLocalization(self):
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Tests different region configurations at OOBE"""
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Save the original device localization settings.
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # To save time, only read initial_locale and keyboard_layout.
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    initial_region = self.Region('', '', '', '', '')
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    initial_region.language_code, _ = self._cri.RunCmdOnDevice(
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ['vpd', '-g', 'initial_locale'])
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    initial_region.keyboard, _ = self._cri.RunCmdOnDevice(
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ['vpd', '-g', 'keyboard_layout'])
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for region in self.REGIONS_LIST:
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self._SwitchRegion(region)
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      with self._CreateBrowser(auto_login=False) as browser:
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Ensure the dropdown lists have been created.
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        util.WaitFor(lambda: browser.oobe.EvaluateJavaScript(
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     'document.getElementById("language-select") != null'),
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     10)
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Find the language, or an acceptable fallback value.
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        languageFound = self._OobeHasOption(browser,
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            'language-select',
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            region.language_code)
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if not languageFound:
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          fallback = self._ResolveLanguage(region.language_code)
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          self.assertTrue(fallback and
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          self._OobeHasOption(browser,
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              'language-select',
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              fallback))
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Find the keyboard layout.
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.assertTrue(self._OobeHasOption(
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            browser, 'keyboard-select', region.keyboard))
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Test is finished. Restore original region settings.
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._SwitchRegion(initial_region)
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # The Region class and region list will be available in regions.py.
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  class Region(object):
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def __init__(self, region_code, keyboard, time_zone, language_code,
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 keyboard_mechanical_layout, description=None, notes=None):
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.region_code = region_code
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.keyboard = keyboard
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.time_zone = time_zone
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.language_code = language_code
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.keyboard_mechanical_layout = keyboard_mechanical_layout
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.description = description or region_code
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.notes = notes
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  class Enum(frozenset):
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def __getattr__(self, name):
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if name in self:
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return name
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      raise AttributeError
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  KeyboardMechanicalLayout = Enum(['ANSI', 'ISO', 'JIS', 'ABNT2'])
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  _KML = KeyboardMechanicalLayout
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  REGIONS_LIST = [
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('au', 'xkb:us::eng', 'Australia/Sydney', 'en-AU', _KML.ANSI,
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           'Australia'),
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('ca.ansi', 'xkb:us::eng', 'America/Toronto', 'en-CA', _KML.ANSI,
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           'Canada (US keyboard)',
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           'Canada with US (ANSI) keyboard; see http://goto/cros-canada'),
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('ca.fr', 'xkb:ca::fra', 'America/Toronto', 'fr-CA', _KML.ISO,
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           'Canada (French keyboard)',
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           ('Canadian French (ISO) keyboard. The most common configuration for '
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'Canadian French SKUs.  See http://goto/cros-canada')),
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('ca.hybrid', 'xkb:ca:eng:eng', 'America/Toronto', 'en-CA', _KML.ISO,
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           'Canada (hybrid)',
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           ('Canada with hybrid xkb:ca:eng:eng + xkb:ca::fra keyboard (ISO), '
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'defaulting to English language and keyboard.  Used only if there '
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'needs to be a single SKU for all of Canada.  See '
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'http://goto/cros-canada')),
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('ca.multix', 'xkb:ca:multix:fra', 'America/Toronto', 'fr-CA',
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           _KML.ISO, 'Canada (multilingual)',
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           ("Canadian Multilingual keyboard; you probably don't want this. See "
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "http://goto/cros-canada")),
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('de', 'xkb:de::ger', 'Europe/Berlin', 'de', _KML.ISO, 'Germany'),
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('fi', 'xkb:fi::fin', 'Europe/Helsinki', 'fi', _KML.ISO, 'Finland'),
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('fr', 'xkb:fr::fra', 'Europe/Paris', 'fr', _KML.ISO, 'France'),
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('gb', 'xkb:gb:extd:eng', 'Europe/London', 'en-GB', _KML.ISO, 'UK'),
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('ie', 'xkb:gb:extd:eng', 'Europe/Dublin', 'en-GB', _KML.ISO,
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           'Ireland'),
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('in', 'xkb:us::eng', 'Asia/Calcutta', 'en-US', _KML.ANSI, 'India'),
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('my', 'xkb:us::eng', 'Asia/Kuala_Lumpur', 'ms', _KML.ANSI,
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           'Malaysia'),
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('nl', 'xkb:us:intl:eng', 'Europe/Amsterdam', 'nl', _KML.ANSI,
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           'Netherlands'),
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('nordic', 'xkb:se::swe', 'Europe/Stockholm', 'en-US', _KML.ISO,
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           'Nordics',
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           ('Unified SKU for Sweden, Norway, and Denmark.  This defaults '
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'to Swedish keyboard layout, but starts with US English language '
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'for neutrality.  Use if there is a single combined SKU for Nordic '
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'countries.')),
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('se', 'xkb:se::swe', 'Europe/Stockholm', 'sv', _KML.ISO, 'Sweden',
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           ("Use this if there separate SKUs for Nordic countries (Sweden, "
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "Norway, and Denmark), or the device is only shipping to Sweden. "
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "If there is a single unified SKU, use 'nordic' instead.")),
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('sg', 'xkb:us::eng', 'Asia/Singapore', 'en-GB', _KML.ANSI,
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           'Singapore'),
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Region('us', 'xkb:us::eng', 'America/Los_Angeles', 'en-US', _KML.ANSI,
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           'United States'),
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ]
325