blob: f5921d0389e78ef85159b671f2cbfd9f1a30af5a [file] [log] [blame]
David Haddock95e7fbe2017-12-01 17:49:53 -08001# 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.
4import json
5import logging
6import os
7import time
8
David Haddock463faf42018-01-23 14:21:11 -08009from autotest_lib.client.common_lib import error
David Haddock95e7fbe2017-12-01 17:49:53 -080010from autotest_lib.client.common_lib import lsbrelease_utils
David Haddock95e7fbe2017-12-01 17:49:53 -080011from autotest_lib.server import autotest
David Haddock95e7fbe2017-12-01 17:49:53 -080012from autotest_lib.server.cros.update_engine import update_engine_test
David Haddockac210892018-02-05 20:36:27 -080013from chromite.lib import retry_util
David Haddock95e7fbe2017-12-01 17:49:53 -080014
15class autoupdate_ForcedOOBEUpdate(update_engine_test.UpdateEngineTest):
16 """Runs a forced autoupdate during OOBE."""
17 version = 1
18
19 # We override the default lsb-release file.
20 _CUSTOM_LSB_RELEASE = '/mnt/stateful_partition/etc/lsb-release'
21
22 # Version we tell the DUT it is on before update.
23 _CUSTOM_LSB_VERSION = '0.0.0.0'
24
25 # Expected hostlog events during update: 4 during rootfs
26 _ROOTFS_HOSTLOG_EVENTS = 4
27
28
David Haddock95e7fbe2017-12-01 17:49:53 -080029 def cleanup(self):
David Haddock95e7fbe2017-12-01 17:49:53 -080030 self._host.run('rm %s' % self._CUSTOM_LSB_RELEASE, ignore_status=True)
31
32 # Get the last two update_engine logs: before and after reboot.
33 files = self._host.run('ls -t -1 '
34 '/var/log/update_engine/').stdout.splitlines()
35 for i in range(2):
36 self._host.get_file('/var/log/update_engine/%s' % files[i],
37 self.resultsdir)
David Haddockac210892018-02-05 20:36:27 -080038 cmd = 'update_engine_client --update_over_cellular=no'
39 retry_util.RetryException(error.AutoservRunError, 2, self._host.run,
40 cmd)
David Haddock50dbfee2018-01-12 12:43:12 -080041 super(autoupdate_ForcedOOBEUpdate, self).cleanup()
David Haddock95e7fbe2017-12-01 17:49:53 -080042
43 def _get_chromeos_version(self):
44 """Read the ChromeOS version from /etc/lsb-release."""
45 lsb = self._host.run('cat /etc/lsb-release').stdout
46 return lsbrelease_utils.get_chromeos_release_version(lsb)
47
48
David Haddock95e7fbe2017-12-01 17:49:53 -080049 def _create_hostlog_files(self):
50 """Create the two hostlog files for the update.
51
52 To ensure the update was succesful we need to compare the update
53 events against expected update events. There is a hostlog for the
54 rootfs update and for the post reboot update check.
55 """
David Haddock14334202017-12-11 13:50:47 -080056 hostlog = self._omaha_devserver.get_hostlog(self._host.ip,
57 wait_for_reboot_events=True)
David Haddock95e7fbe2017-12-01 17:49:53 -080058 logging.info('Hostlog: %s', hostlog)
59
60 # File names to save the hostlog events to.
61 rootfs_hostlog = os.path.join(self.resultsdir, 'hostlog_rootfs')
62 reboot_hostlog = os.path.join(self.resultsdir, 'hostlog_reboot')
63
64 with open(rootfs_hostlog, 'w') as outfile:
65 json.dump(hostlog[:self._ROOTFS_HOSTLOG_EVENTS], outfile)
66 with open(reboot_hostlog, 'w') as outfile:
67 json.dump(hostlog[self._ROOTFS_HOSTLOG_EVENTS:], outfile)
68 return rootfs_hostlog, reboot_hostlog
69
70
71 def _wait_for_update_to_complete(self):
72 """Wait for the update that started to complete.
73
74 Repeated check status of update. It should move from DOWNLOADING to
75 FINALIZING to COMPLETE to IDLE.
76 """
77 while True:
78 status = self._host.run('update_engine_client --status',
79 ignore_timeout=True,
80 timeout=10)
81
82 # During reboot, status will be None
83 if status is not None:
84 status = status.stdout.splitlines()
85 logging.debug(status)
86 if "UPDATE_STATUS_IDLE" in status[2]:
87 break
88 time.sleep(1)
89
90
David Haddockac210892018-02-05 20:36:27 -080091 def run_once(self, host, full_payload=True, cellular=False,
92 job_repo_url=None):
David Haddock95e7fbe2017-12-01 17:49:53 -080093 self._host = host
David Haddock463faf42018-01-23 14:21:11 -080094
95 # veyron_rialto is a medical device with a different OOBE that auto
96 # completes so this test is not valid on that device.
97 if 'veyron_rialto' in self._host.get_board():
98 raise error.TestNAError('Rialto has a custom OOBE. Skipping test.')
99
David Haddock50dbfee2018-01-12 12:43:12 -0800100 update_url = self.get_update_url_for_test(job_repo_url,
David Haddock463faf42018-01-23 14:21:11 -0800101 full_payload=full_payload,
David Haddockac210892018-02-05 20:36:27 -0800102 critical_update=True,
103 cellular=cellular)
David Haddock50dbfee2018-01-12 12:43:12 -0800104 logging.info('Update url: %s', update_url)
David Haddock95e7fbe2017-12-01 17:49:53 -0800105 before = self._get_chromeos_version()
David Haddockac210892018-02-05 20:36:27 -0800106 payload_info = None
107 if cellular:
108 cmd = 'update_engine_client --update_over_cellular=yes'
109 retry_util.RetryException(error.AutoservRunError, 2, self._host.run,
110 cmd)
111 # Get the payload's information (size, SHA256 etc) since we will be
112 # setting up our own omaha instance on the DUT. We pass this to
113 # the client test.
114 payload = self._get_payload_url(full_payload=full_payload)
115 staged_url = self._stage_payload_by_uri(payload)
116 payload_info = self._get_staged_file_info(staged_url)
David Haddock95e7fbe2017-12-01 17:49:53 -0800117
118 # Call client test to start the forced OOBE update.
119 client_at = autotest.Autotest(self._host)
David Haddockac210892018-02-05 20:36:27 -0800120 client_at.run_test('autoupdate_StartOOBEUpdate', image_url=update_url,
121 cellular=cellular, payload_info=payload_info,
122 full_payload=full_payload)
David Haddock95e7fbe2017-12-01 17:49:53 -0800123
124 # Don't continue the test if the client failed for any reason.
125 client_at._check_client_test_result(self._host,
126 'autoupdate_StartOOBEUpdate')
127
128 self._wait_for_update_to_complete()
129
David Haddockac210892018-02-05 20:36:27 -0800130 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.
136 update_engine_files_cmd = 'ls -t -1 /var/log/update_engine/'
137 files = self._host.run(update_engine_files_cmd).stdout.splitlines()
138 before_reboot_file = self._host.run('cat /var/log/update_engine/%s'
139 % files[1]).stdout
140 self._check_for_cellular_entries_in_update_log(before_reboot_file)
141
142 success = 'Update successfully applied, waiting to reboot.'
143 update_ec = self._host.run('cat /var/log/update_engine/%s | grep '
144 '"%s"' % (files[1], success)).exit_status
145 if update_ec != 0:
146 raise error.TestFail('We could not verify that the update '
147 'completed successfully. Check the logs.')
148 return
149
David Haddock95e7fbe2017-12-01 17:49:53 -0800150 # Verify that the update completed successfully by checking hostlog.
151 rootfs_hostlog, reboot_hostlog = self._create_hostlog_files()
152 self.verify_update_events(self._CUSTOM_LSB_VERSION, rootfs_hostlog)
153 self.verify_update_events(self._CUSTOM_LSB_VERSION, reboot_hostlog,
154 self._CUSTOM_LSB_VERSION)
155
156 after = self._get_chromeos_version()
157 logging.info('Successfully force updated from %s to %s.', before, after)