1# Lint as: python2, python3 2# Copyright 2020 The Chromium OS Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import logging 7 8from autotest_lib.client.bin import utils 9from autotest_lib.client.common_lib import error 10from autotest_lib.client.common_lib.cros import chrome 11from autotest_lib.client.cros.update_engine import nebraska_wrapper 12from autotest_lib.client.cros.update_engine import update_engine_test 13from telemetry.core import exceptions 14 15class autoupdate_UpdateFromUI(update_engine_test.UpdateEngineTest): 16 """Starts an update from the ChromeOS Settings app. """ 17 version = 1 18 19 _NOTIFICATION_INTERVAL = 1 20 _NOTIFICATION_TIMEOUT = 10 21 _NOTIFICATION_TITLE = "Update available" 22 23 24 def initialize(self): 25 """Test setup.""" 26 super(autoupdate_UpdateFromUI, self).initialize() 27 self._clear_custom_lsb_release() 28 self._cr = None 29 30 31 def cleanup(self): 32 """Test cleanup. Clears the custom lsb-release used by the test. """ 33 self._clear_custom_lsb_release() 34 super(autoupdate_UpdateFromUI, self).cleanup() 35 36 def _wait_for_update_notification(self): 37 """Waits for the post-update notification to appear. """ 38 39 def find_notification(): 40 """Polls for visibility of the post-update notification. """ 41 notifications = self._cr.get_visible_notifications() 42 if notifications is None: 43 return False 44 return any(n for n in notifications 45 if self._NOTIFICATION_TITLE in n['title']) 46 47 utils.poll_for_condition( 48 condition=find_notification, 49 exception=error.TestFail('Post-update notification not found'), 50 timeout=self._NOTIFICATION_TIMEOUT, 51 sleep_interval=self._NOTIFICATION_INTERVAL) 52 53 54 def run_once(self, payload_url): 55 """ 56 Tests that a ChromeOS software update can be completed from the UI, 57 and that the post-update notification appears when the update is 58 complete. 59 60 @param payload_url: The payload url to use. 61 62 """ 63 with nebraska_wrapper.NebraskaWrapper( 64 log_dir=self.resultsdir, payload_url=payload_url) as nebraska: 65 # To check the post-update notification, we need to remain logged 66 # in after the update completes. However, the DUT will auto-reboot 67 # if we log out after completing an update. This will cause the 68 # server test to fail when returning from the client test. To avoid 69 # this, we stay logged in at the end of the client test by not 70 # using a context manager for the Chrome session. 71 try: 72 self._cr = chrome.Chrome(autotest_ext=True) 73 74 # Need to create a custom lsb-release file to point the UI 75 # update button to Nebraska instead of the default update 76 # server. 77 self._create_custom_lsb_release( 78 nebraska.get_update_url(critical_update=True)) 79 80 # Go to the OS settings page and check for an update. 81 tab = self._cr.browser.tabs[0] 82 tab.Navigate('chrome://os-settings/help') 83 tab.WaitForDocumentReadyStateToBeComplete() 84 self._take_screenshot('before_check_for_updates.png') 85 request_update_js = ''' 86 async function checkForUpdate() { 87 return await import('chrome://os-settings/chromeos/os_settings.js').then(m => 88 m.AboutPageBrowserProxyImpl.getInstance().requestUpdate()); 89 } 90 checkForUpdate(); 91 ''' 92 try: 93 tab.EvaluateJavaScript(request_update_js) 94 except exceptions.EvaluateException: 95 raise error.TestFail( 96 'Failed to find and click Check For Updates button.') 97 self._take_screenshot('after_check_for_updates.png') 98 self._wait_for_update_to_complete() 99 100 except Exception as e: 101 # The update didn't complete, so we can close the Chrome 102 # session without worrying about auto-reboot. 103 logging.exception("Failed to perform the update: %s", e) 104 if self._cr: 105 self._cr.close() 106 raise error.TestFail("Failed to perform the update: %s" % e) 107 108 self._wait_for_update_notification() 109