1# Lint as: python2, python3 2# Copyright 2018 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 datetime 7import logging 8 9from autotest_lib.client.bin import utils 10from autotest_lib.client.common_lib import error 11from autotest_lib.client.common_lib.cros import chrome 12from autotest_lib.client.cros.update_engine import nebraska_wrapper 13from autotest_lib.client.cros.update_engine import update_engine_test 14 15class autoupdate_EOL(update_engine_test.UpdateEngineTest): 16 """Tests end of life (EOL) behaviour.""" 17 version = 1 18 19 _EXPECTED_FINAL_TITLE = 'Final software update' 20 _DAYS_BEFORE_EOL_START_WARNING = 180 21 # Value within {} expected to be number of days since epoch. 22 _EXPECTED_EOL_DATE_TEMPLATE = 'EOL_DATE={}' 23 # Value within {} expected to be the month and year. 24 _EXPECTED_WARNING_TITLE = 'Updates end {}' 25 _UNIX_EPOCH = datetime.datetime(1970, 1, 1) 26 27 28 def _get_expected_eol_date(self, eol_date): 29 """Figure out the expected eol date.""" 30 return self._UNIX_EPOCH + datetime.timedelta(eol_date) 31 32 33 def _check_eol_info(self): 34 """Checks update_engines eol status.""" 35 result = utils.run( 36 [self._UPDATE_ENGINE_CLIENT_CMD, '--eol_status']).stdout.strip() 37 if self._EXPECTED_EOL_DATE not in result: 38 raise error.TestFail('Expected date %s. Actual: %s' % 39 (self._EXPECTED_EOL_DATE, result)) 40 41 42 def _check_eol_notification(self, eol_date): 43 """Checks that we are showing an EOL notification to the user.""" 44 expected_eol_date = self._get_expected_eol_date(eol_date) 45 expected_warning_begins_date = (expected_eol_date 46 - datetime.timedelta( 47 self._DAYS_BEFORE_EOL_START_WARNING)) 48 49 expected_final_title = self._EXPECTED_FINAL_TITLE 50 expected_warning_title = (self._EXPECTED_WARNING_TITLE. 51 format(expected_eol_date.strftime("%B %Y"))) 52 53 def find_notification(expected_title): 54 """Helper to find notification.""" 55 notifications = self._cr.get_visible_notifications() 56 return any([n['title'] == expected_title 57 for n in (notifications or [])]) 58 59 def check_eol_notifications(): 60 """Checks if correct notification is shown.""" 61 final_notification = find_notification(expected_final_title) 62 warning_notification = find_notification(expected_warning_title) 63 64 now = datetime.datetime.utcnow() 65 if expected_eol_date <= now: 66 return final_notification and not warning_notification 67 elif expected_warning_begins_date <= now: 68 return not final_notification and warning_notification 69 return not final_notification and not warning_notification 70 71 utils.poll_for_condition(condition=lambda: check_eol_notifications(), 72 desc='End of Life Notification UI passed', 73 timeout=5, sleep_interval=1) 74 75 76 def _check_eol_settings(self, eol_date): 77 """Check that the messages about EOL in Settings are correct.""" 78 tab = self._cr.browser.tabs[0] 79 tab.Navigate('chrome://os-settings/help/details') 80 tab.WaitForDocumentReadyStateToBeComplete() 81 eol_js = ''' 82 async function getEOL() { 83 return await import('chrome://os-settings/chromeos/os_settings.js').then(m => 84 m.AboutPageBrowserProxyImpl.getInstance().getEndOfLifeInfo()); 85 } 86 getEOL(); 87 ''' 88 eol_promise = tab.EvaluateJavaScript(eol_js, promise=True) 89 expected_eol_date = self._get_expected_eol_date(eol_date) 90 eol_msg = ('This device will get automatic software and security ' 91 'updates until') 92 if expected_eol_date <= datetime.datetime.utcnow(): 93 eol_msg = ('This device stopped getting automatic software and ' 94 'security updates in') 95 if eol_msg not in eol_promise['aboutPageEndOfLifeMessage']: 96 raise error.TestFail('"%s" not found in Settings.' % eol_msg) 97 98 99 def run_once(self, eol_date): 100 """ 101 Checks that DUT behaves correctly in EOL scenarios. 102 103 @param eol_date: the days from epoch value passed along to 104 NanoOmahaDevServer placed within the _eol_date tag 105 in the Omaha response. 106 107 """ 108 self._EXPECTED_EOL_DATE = \ 109 self._EXPECTED_EOL_DATE_TEMPLATE.format(eol_date) 110 111 # Start a Nebraska server to return a response with eol entry. 112 with nebraska_wrapper.NebraskaWrapper( 113 log_dir=self.resultsdir) as nebraska: 114 # Try to update. It should fail with noupdate. 115 try: 116 self._check_for_update( 117 nebraska.get_update_url(eol_date=eol_date, no_update=True), 118 wait_for_completion=True) 119 except error.CmdError: 120 logging.info('Update failed as expected.') 121 122 self._check_eol_info() 123 with chrome.Chrome(autotest_ext=True, logged_in=True) as cr: 124 self._cr = cr 125 self._check_eol_notification(eol_date) 126 self._check_eol_settings(eol_date) 127