David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 1 | # Copyright 2017 The Chromium OS 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. |
David Haddock | 80e3b8f | 2018-04-10 17:44:43 -0700 | [diff] [blame] | 4 | |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 5 | import logging |
David Haddock | 0bad4a3 | 2018-02-02 13:05:26 -0800 | [diff] [blame] | 6 | import random |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 7 | import time |
| 8 | |
David Haddock | 463faf4 | 2018-01-23 14:21:11 -0800 | [diff] [blame] | 9 | from autotest_lib.client.common_lib import error |
David Haddock | 3a8f572 | 2018-04-13 16:24:16 -0700 | [diff] [blame] | 10 | from autotest_lib.client.common_lib.cros import tpm_utils |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 11 | from autotest_lib.server.cros.update_engine import update_engine_test |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 12 | |
| 13 | class autoupdate_ForcedOOBEUpdate(update_engine_test.UpdateEngineTest): |
| 14 | """Runs a forced autoupdate during OOBE.""" |
| 15 | version = 1 |
| 16 | |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 17 | |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 18 | def cleanup(self): |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 19 | self._host.run('rm %s' % self._CUSTOM_LSB_RELEASE, ignore_status=True) |
| 20 | |
| 21 | # Get the last two update_engine logs: before and after reboot. |
David Haddock | 2fd9aec | 2018-04-23 19:17:46 -0700 | [diff] [blame] | 22 | self._save_extra_update_engine_logs() |
| 23 | self._change_cellular_setting_in_update_engine(False) |
David Haddock | b1733c8 | 2018-09-07 09:43:57 -0700 | [diff] [blame] | 24 | |
| 25 | # Cancel any update still in progress. |
| 26 | if not self._is_update_engine_idle(): |
| 27 | logging.debug('Canceling the in-progress update.') |
| 28 | self._host.run('restart update-engine') |
David Haddock | 50dbfee | 2018-01-12 12:43:12 -0800 | [diff] [blame] | 29 | super(autoupdate_ForcedOOBEUpdate, self).cleanup() |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 30 | |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 31 | |
David Haddock | 80e3b8f | 2018-04-10 17:44:43 -0700 | [diff] [blame] | 32 | def _wait_for_oobe_update_to_complete(self): |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 33 | """Wait for the update that started to complete. |
| 34 | |
| 35 | Repeated check status of update. It should move from DOWNLOADING to |
David Haddock | 80e3b8f | 2018-04-10 17:44:43 -0700 | [diff] [blame] | 36 | FINALIZING to COMPLETE (then reboot) to IDLE. |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 37 | """ |
David Haddock | eb31142 | 2019-07-22 17:14:58 -0700 | [diff] [blame] | 38 | timeout_minutes = 10 |
David Haddock | 5e2ef31 | 2018-06-12 12:59:31 -0700 | [diff] [blame] | 39 | timeout = time.time() + 60 * timeout_minutes |
David Haddock | eb31142 | 2019-07-22 17:14:58 -0700 | [diff] [blame] | 40 | boot_id = self._host.get_boot_id() |
| 41 | |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 42 | while True: |
David Haddock | 3ffa134 | 2019-12-10 19:35:32 -0800 | [diff] [blame] | 43 | try: |
| 44 | self._get_update_engine_status(timeout=10, |
| 45 | ignore_timeout=False) |
| 46 | except error.AutoservRunError as e: |
| 47 | # Check if command timed out because update-engine was taking |
| 48 | # a while or if the command didn't even start. |
| 49 | query = 'Querying Update Engine status...' |
| 50 | if query not in e.result_obj.stderr: |
| 51 | # Command did not start. DUT rebooted at end of update. |
| 52 | self._host.test_wait_for_boot(boot_id) |
| 53 | break |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 54 | |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 55 | time.sleep(1) |
David Haddock | 5e2ef31 | 2018-06-12 12:59:31 -0700 | [diff] [blame] | 56 | if time.time() > timeout: |
| 57 | raise error.TestFail('OOBE update did not finish in %d ' |
| 58 | 'minutes.' % timeout_minutes) |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 59 | |
| 60 | |
David Haddock | 2fd9aec | 2018-04-23 19:17:46 -0700 | [diff] [blame] | 61 | def run_once(self, full_payload=True, cellular=False, |
Amin Hassani | f56f5c6 | 2020-02-14 16:31:31 -0800 | [diff] [blame] | 62 | interrupt=None, job_repo_url=None, moblab=False): |
David Haddock | 0bad4a3 | 2018-02-02 13:05:26 -0800 | [diff] [blame] | 63 | """ |
| 64 | Runs a forced autoupdate during ChromeOS OOBE. |
| 65 | |
David Haddock | 0bad4a3 | 2018-02-02 13:05:26 -0800 | [diff] [blame] | 66 | @param full_payload: True for a full payload. False for delta. |
| 67 | @param cellular: True to do the update over a cellualar connection. |
| 68 | Requires that the DUT have a sim card slot. |
David Haddock | 8efca4d | 2019-07-23 19:08:03 -0700 | [diff] [blame] | 69 | @param interrupt: Type of interrupt to try: [reboot, network, suspend] |
David Haddock | 0bad4a3 | 2018-02-02 13:05:26 -0800 | [diff] [blame] | 70 | @param job_repo_url: Used for debugging locally. This is used to figure |
| 71 | out the current build and the devserver to use. |
| 72 | The test will read this from a host argument |
| 73 | when run in the lab. |
David Haddock | 95c74c0 | 2019-09-16 11:06:33 -0700 | [diff] [blame] | 74 | @param moblab: True if we are running on moblab. |
David Haddock | 0bad4a3 | 2018-02-02 13:05:26 -0800 | [diff] [blame] | 75 | |
| 76 | """ |
David Haddock | 463faf4 | 2018-01-23 14:21:11 -0800 | [diff] [blame] | 77 | # veyron_rialto is a medical device with a different OOBE that auto |
| 78 | # completes so this test is not valid on that device. |
| 79 | if 'veyron_rialto' in self._host.get_board(): |
| 80 | raise error.TestNAError('Rialto has a custom OOBE. Skipping test.') |
| 81 | |
David Haddock | 8efca4d | 2019-07-23 19:08:03 -0700 | [diff] [blame] | 82 | tpm_utils.ClearTPMOwnerRequest(self._host) |
David Haddock | 50dbfee | 2018-01-12 12:43:12 -0800 | [diff] [blame] | 83 | update_url = self.get_update_url_for_test(job_repo_url, |
David Haddock | 463faf4 | 2018-01-23 14:21:11 -0800 | [diff] [blame] | 84 | full_payload=full_payload, |
David Haddock | ac21089 | 2018-02-05 20:36:27 -0800 | [diff] [blame] | 85 | critical_update=True, |
David Haddock | 80e3b8f | 2018-04-10 17:44:43 -0700 | [diff] [blame] | 86 | public=cellular, |
David Haddock | 95c74c0 | 2019-09-16 11:06:33 -0700 | [diff] [blame] | 87 | moblab=moblab) |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 88 | before = self._get_chromeos_version() |
David Haddock | ac21089 | 2018-02-05 20:36:27 -0800 | [diff] [blame] | 89 | payload_info = None |
| 90 | if cellular: |
David Haddock | 2fd9aec | 2018-04-23 19:17:46 -0700 | [diff] [blame] | 91 | self._change_cellular_setting_in_update_engine(True) |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 92 | |
| 93 | # Call client test to start the forced OOBE update. |
David Haddock | 80e3b8f | 2018-04-10 17:44:43 -0700 | [diff] [blame] | 94 | self._run_client_test_and_check_result('autoupdate_StartOOBEUpdate', |
| 95 | image_url=update_url, |
Amin Hassani | 151b73b | 2020-01-30 16:44:52 -0800 | [diff] [blame] | 96 | cellular=cellular) |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 97 | |
David Haddock | 8efca4d | 2019-07-23 19:08:03 -0700 | [diff] [blame] | 98 | if interrupt is not None: |
David Haddock | 80e3b8f | 2018-04-10 17:44:43 -0700 | [diff] [blame] | 99 | # Choose a random downloaded progress to interrupt the update. |
David Haddock | 8efca4d | 2019-07-23 19:08:03 -0700 | [diff] [blame] | 100 | progress = random.uniform(0.1, 0.6) |
| 101 | logging.info('Progress when we will interrupt: %f', progress) |
David Haddock | 80e3b8f | 2018-04-10 17:44:43 -0700 | [diff] [blame] | 102 | self._wait_for_progress(progress) |
David Haddock | 8efca4d | 2019-07-23 19:08:03 -0700 | [diff] [blame] | 103 | logging.info('We will now start interrupting the update.') |
| 104 | self._take_screenshot('before_interrupt.png') |
David Haddock | ed70eef | 2018-07-19 16:40:54 -0700 | [diff] [blame] | 105 | completed = self._get_update_progress() |
David Haddock | 8efca4d | 2019-07-23 19:08:03 -0700 | [diff] [blame] | 106 | |
| 107 | if interrupt is 'reboot': |
| 108 | self._host.reboot() |
| 109 | elif interrupt is 'network': |
| 110 | self._disconnect_then_reconnect_network(update_url) |
| 111 | elif interrupt is 'suspend': |
| 112 | self._suspend_then_resume() |
| 113 | else: |
| 114 | raise error.TestFail('Unknown interrupt type: %s' % interrupt) |
| 115 | # Screenshot to check that OOBE was not skipped by interruption. |
| 116 | self._take_screenshot('after_interrupt.png') |
| 117 | |
David Haddock | afdfa5b | 2018-08-10 16:10:01 -0700 | [diff] [blame] | 118 | if self._is_update_engine_idle(): |
David Haddock | 8efca4d | 2019-07-23 19:08:03 -0700 | [diff] [blame] | 119 | raise error.TestFail('The update was IDLE after interrupt.') |
David Haddock | 0bad4a3 | 2018-02-02 13:05:26 -0800 | [diff] [blame] | 120 | if not self._update_continued_where_it_left_off(completed): |
| 121 | raise error.TestFail('The update did not continue where it ' |
David Haddock | 8efca4d | 2019-07-23 19:08:03 -0700 | [diff] [blame] | 122 | 'left off after interruption.') |
David Haddock | 0bad4a3 | 2018-02-02 13:05:26 -0800 | [diff] [blame] | 123 | |
Amin Hassani | f56f5c6 | 2020-02-14 16:31:31 -0800 | [diff] [blame] | 124 | # We create a new lsb-release file with no_update=True so there won't be |
| 125 | # any more actual updates happen. |
| 126 | self._create_custom_lsb_release(update_url, no_update=True) |
| 127 | |
David Haddock | 80e3b8f | 2018-04-10 17:44:43 -0700 | [diff] [blame] | 128 | self._wait_for_oobe_update_to_complete() |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 129 | |
David Haddock | ac21089 | 2018-02-05 20:36:27 -0800 | [diff] [blame] | 130 | if cellular: |
| 131 | # We didn't have a devserver so we cannot check the hostlog to |
| 132 | # ensure the update completed successfully. Instead we can check |
| 133 | # that the second-to-last update engine log has the successful |
| 134 | # update message. Second to last because its the one before OOBE |
| 135 | # rebooted. |
David Haddock | 2fd9aec | 2018-04-23 19:17:46 -0700 | [diff] [blame] | 136 | before_reboot_file = self._get_second_last_update_engine_log() |
David Haddock | ac21089 | 2018-02-05 20:36:27 -0800 | [diff] [blame] | 137 | self._check_for_cellular_entries_in_update_log(before_reboot_file) |
David Haddock | ac21089 | 2018-02-05 20:36:27 -0800 | [diff] [blame] | 138 | success = 'Update successfully applied, waiting to reboot.' |
David Haddock | 2fd9aec | 2018-04-23 19:17:46 -0700 | [diff] [blame] | 139 | self._check_update_engine_log_for_entry(success, |
| 140 | raise_error=True, |
| 141 | update_engine_log= |
| 142 | before_reboot_file) |
David Haddock | ac21089 | 2018-02-05 20:36:27 -0800 | [diff] [blame] | 143 | return |
| 144 | |
David Haddock | 95e7fbe | 2017-12-01 17:49:53 -0800 | [diff] [blame] | 145 | # Verify that the update completed successfully by checking hostlog. |
| 146 | rootfs_hostlog, reboot_hostlog = self._create_hostlog_files() |
| 147 | self.verify_update_events(self._CUSTOM_LSB_VERSION, rootfs_hostlog) |
| 148 | self.verify_update_events(self._CUSTOM_LSB_VERSION, reboot_hostlog, |
| 149 | self._CUSTOM_LSB_VERSION) |
| 150 | |
| 151 | after = self._get_chromeos_version() |
| 152 | logging.info('Successfully force updated from %s to %s.', before, after) |