# Copyright 2018 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import datetime import logging from autotest_lib.client.bin import utils from autotest_lib.client.common_lib import error from autotest_lib.client.common_lib.cros import chrome from autotest_lib.client.cros.update_engine import nebraska_wrapper from autotest_lib.client.cros.update_engine import update_engine_test class autoupdate_EOL(update_engine_test.UpdateEngineTest): """Tests end of life (EOL) behaviour.""" version = 1 _EXPECTED_FINAL_TITLE = 'Final software update' _DAYS_BEFORE_EOL_START_WARNING = 180 # Value within {} expected to be number of days since epoch. _EXPECTED_EOL_DATE_TEMPLATE = 'EOL_DATE={}' # Value within {} expected to be the month and year. _EXPECTED_WARNING_TITLE = 'Updates end {}' _UNIX_EPOCH = datetime.datetime(1970, 1, 1) def _get_expected_eol_date(self, eol_date): """Figure out the expected eol date.""" return self._UNIX_EPOCH + datetime.timedelta(eol_date) def _check_eol_info(self): """Checks update_engines eol status.""" result = utils.run( [self._UPDATE_ENGINE_CLIENT_CMD, '--eol_status']).stdout.strip() if self._EXPECTED_EOL_DATE not in result: raise error.TestFail('Expected date %s. Actual: %s' % (self._EXPECTED_EOL_DATE, result)) def _check_eol_notification(self, eol_date): """Checks that we are showing an EOL notification to the user.""" expected_eol_date = self._get_expected_eol_date(eol_date) expected_warning_begins_date = (expected_eol_date - datetime.timedelta( self._DAYS_BEFORE_EOL_START_WARNING)) expected_final_title = self._EXPECTED_FINAL_TITLE expected_warning_title = (self._EXPECTED_WARNING_TITLE. format(expected_eol_date.strftime("%B %Y"))) def find_notification(expected_title): """Helper to find notification.""" notifications = self._cr.get_visible_notifications() return any([n['title'] == expected_title for n in (notifications or [])]) def check_eol_notifications(): """Checks if correct notification is shown.""" final_notification = find_notification(expected_final_title) warning_notification = find_notification(expected_warning_title) now = datetime.datetime.utcnow() if expected_eol_date <= now: return final_notification and not warning_notification elif expected_warning_begins_date <= now: return not final_notification and warning_notification return not final_notification and not warning_notification utils.poll_for_condition(condition=lambda: check_eol_notifications(), desc='End of Life Notification UI passed', timeout=5, sleep_interval=1) def _check_eol_settings(self, eol_date): """Check that the messages about EOL in Settings are correct.""" tab = self._cr.browser.tabs[0] tab.Navigate('chrome://os-settings/help/details') tab.WaitForDocumentReadyStateToBeComplete() eol_js = ''' settings.AboutPageBrowserProxyImpl.getInstance().getEndOfLifeInfo() ''' eol_promise = tab.EvaluateJavaScript(eol_js, promise=True) expected_eol_date = self._get_expected_eol_date(eol_date) eol_msg = ('This device will get automatic software and security ' 'updates until') if expected_eol_date <= datetime.datetime.utcnow(): eol_msg = ('This device stopped getting automatic software and ' 'security updates in') if eol_msg not in eol_promise['aboutPageEndOfLifeMessage']: raise error.TestFail('"%s" not found in Settings.' % eol_msg) def run_once(self, eol_date): """ Checks that DUT behaves correctly in EOL scenarios. @param eol_date: the days from epoch value passed along to NanoOmahaDevServer placed within the _eol_date tag in the Omaha response. """ self._EXPECTED_EOL_DATE = \ self._EXPECTED_EOL_DATE_TEMPLATE.format(eol_date) # Start a Nebraska server to return a response with eol entry. with nebraska_wrapper.NebraskaWrapper( log_dir=self.resultsdir) as nebraska: # Try to update. It should fail with noupdate. try: self._check_for_update( nebraska.get_update_url(eol_date=eol_date, no_update=True), wait_for_completion=True) except error.CmdError: logging.info('Update failed as expected.') self._check_eol_info() with chrome.Chrome(autotest_ext=True, logged_in=True) as cr: self._cr = cr self._check_eol_notification(eol_date) self._check_eol_settings(eol_date)