blob: 63dc0d7463fa23b8b6ba75ac5be2bcfb37136f28 [file] [log] [blame]
Scott Zawalskieadbf702013-03-14 09:23:06 -04001#!/usr/bin/python
2# Copyright (c) 2013 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
Dan Shib95bb862013-03-22 16:29:28 -07006import mox
Scott Zawalskieadbf702013-03-14 09:23:06 -04007import unittest
8
9import common
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -080010import time
Scott Zawalskieadbf702013-03-14 09:23:06 -040011
12import autoupdater
Don Garrettdf8aef72013-12-16 11:12:41 -080013from autotest_lib.client.common_lib import error
Scott Zawalskieadbf702013-03-14 09:23:06 -040014
Dan Shib95bb862013-03-22 16:29:28 -070015class TestAutoUpdater(mox.MoxTestBase):
Scott Zawalskieadbf702013-03-14 09:23:06 -040016 """Test autoupdater module."""
17
18
19 def testParseBuildFromUpdateUrlwithUpdate(self):
20 """Test that we properly parse the build from an update_url."""
21 update_url = ('http://172.22.50.205:8082/update/lumpy-release/'
22 'R27-3837.0.0')
23 expected_value = 'lumpy-release/R27-3837.0.0'
24 self.assertEqual(autoupdater.url_to_image_name(update_url),
25 expected_value)
26
27
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -080028 def _host_run_for_update(self, cmd, exception=None,
29 bad_update_status=False):
30 """Helper function for AU tests.
31
32 @param host: the test host
33 @param cmd: the command to be recorded
34 @param exception: the exception to be recorded, or None
35 """
36 if exception:
37 self.host.run(command=cmd).AndRaise(exception)
38 else:
39 result = self.mox.CreateMockAnything()
40 if bad_update_status:
41 # Pick randomly one unexpected status
42 result.stdout = 'UPDATE_STATUS_UPDATED_NEED_REBOOT'
43 else:
44 result.stdout = 'UPDATE_STATUS_IDLE'
45 result.status = 0
46 self.host.run(command=cmd).AndReturn(result)
47
48
Don Garrettdf8aef72013-12-16 11:12:41 -080049 def testTriggerUpdate(self):
50 """Tests that we correctly handle updater errors."""
Don Garrettdf8aef72013-12-16 11:12:41 -080051 update_url = 'http://server/test/url'
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -080052 self.host = self.mox.CreateMockAnything()
53 self.mox.StubOutWithMock(self.host, 'run')
Shuqian Zhaod9992722016-02-29 12:26:38 -080054 self.mox.StubOutWithMock(autoupdater.ChromiumOSUpdater,
Richard Barnette3e8b2282018-05-15 20:42:20 +000055 '_get_last_update_error')
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -080056 self.host.hostname = 'test_host'
57 updater_control_bin = '/usr/bin/update_engine_client'
58 test_url = 'http://server/test/url'
59 expected_wait_cmd = ('%s -status | grep CURRENT_OP' %
60 updater_control_bin)
61 expected_cmd = ('%s --check_for_update --omaha_url=%s' %
62 (updater_control_bin, test_url))
63 self.mox.StubOutWithMock(time, "sleep")
64 UPDATE_ENGINE_RETRY_WAIT_TIME=5
Don Garrettdf8aef72013-12-16 11:12:41 -080065
Luigi Semenzatoe76d9f82016-11-21 11:15:10 -080066 # Generic SSH Error.
Don Garrettdf8aef72013-12-16 11:12:41 -080067 cmd_result_255 = self.mox.CreateMockAnything()
68 cmd_result_255.exit_status = 255
69
Shuqian Zhaod9992722016-02-29 12:26:38 -080070 # Command Failed Error
71 cmd_result_1 = self.mox.CreateMockAnything()
72 cmd_result_1.exit_status = 1
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -080073
74 # Error 37
75 cmd_result_37 = self.mox.CreateMockAnything()
76 cmd_result_37.exit_status = 37
77
78 updater = autoupdater.ChromiumOSUpdater(update_url, host=self.host)
79
80 # (SUCCESS) Expect one wait command and one status command.
81 self._host_run_for_update(expected_wait_cmd)
82 self._host_run_for_update(expected_cmd)
83
84 # (SUCCESS) Test with one retry to wait for update-engine.
85 self._host_run_for_update(expected_wait_cmd, exception=
86 error.AutoservRunError('non-zero status', cmd_result_1))
87 time.sleep(UPDATE_ENGINE_RETRY_WAIT_TIME)
88 self._host_run_for_update(expected_wait_cmd)
89 self._host_run_for_update(expected_cmd)
90
91 # (SUCCESS) One-time SSH timeout, then success on retry.
92 self._host_run_for_update(expected_wait_cmd)
93 self._host_run_for_update(expected_cmd, exception=
94 error.AutoservSSHTimeout('ssh timed out', cmd_result_255))
95 self._host_run_for_update(expected_cmd)
96
97 # (SUCCESS) One-time ERROR 37, then success.
98 self._host_run_for_update(expected_wait_cmd)
99 self._host_run_for_update(expected_cmd, exception=
100 error.AutoservRunError('ERROR_CODE=37', cmd_result_37))
101 self._host_run_for_update(expected_cmd)
102
103 # (FAILURE) Bad status of update engine.
104 self._host_run_for_update(expected_wait_cmd)
105 self._host_run_for_update(expected_cmd, bad_update_status=True,
106 exception=error.InstallError(
107 'host is not in installable state'))
108
109 # (FAILURE) Two-time SSH timeout.
110 self._host_run_for_update(expected_wait_cmd)
111 self._host_run_for_update(expected_cmd, exception=
112 error.AutoservSSHTimeout('ssh timed out', cmd_result_255))
113 self._host_run_for_update(expected_cmd, exception=
114 error.AutoservSSHTimeout('ssh timed out', cmd_result_255))
115
116 # (FAILURE) SSH Permission Error
117 self._host_run_for_update(expected_wait_cmd)
118 self._host_run_for_update(expected_cmd, exception=
119 error.AutoservSshPermissionDeniedError('no permission',
120 cmd_result_255))
121
122 # (FAILURE) Other ssh failure
123 self._host_run_for_update(expected_wait_cmd)
124 self._host_run_for_update(expected_cmd, exception=
125 error.AutoservSshPermissionDeniedError('no permission',
126 cmd_result_255))
127 # (FAILURE) Other error
128 self._host_run_for_update(expected_wait_cmd)
129 self._host_run_for_update(expected_cmd, exception=
Luigi Semenzatoe76d9f82016-11-21 11:15:10 -0800130 error.AutoservRunError("unknown error", cmd_result_1))
Shuqian Zhaod9992722016-02-29 12:26:38 -0800131
Don Garrettdf8aef72013-12-16 11:12:41 -0800132 self.mox.ReplayAll()
133
Luigi Semenzatoe76d9f82016-11-21 11:15:10 -0800134 # Expect success
135 updater.trigger_update()
136 updater.trigger_update()
Don Garrettdf8aef72013-12-16 11:12:41 -0800137 updater.trigger_update()
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -0800138 updater.trigger_update()
Don Garrettdf8aef72013-12-16 11:12:41 -0800139
Luigi Semenzatoe76d9f82016-11-21 11:15:10 -0800140 # Expect errors as listed above
141 self.assertRaises(autoupdater.RootFSUpdateError, updater.trigger_update)
142 self.assertRaises(autoupdater.RootFSUpdateError, updater.trigger_update)
143 self.assertRaises(autoupdater.RootFSUpdateError, updater.trigger_update)
144 self.assertRaises(autoupdater.RootFSUpdateError, updater.trigger_update)
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -0800145 self.assertRaises(autoupdater.RootFSUpdateError, updater.trigger_update)
Don Garrettdf8aef72013-12-16 11:12:41 -0800146
147 self.mox.VerifyAll()
148
149
Chris Sosa72312602013-04-16 15:01:56 -0700150 def testUpdateStateful(self):
151 """Tests that we call the stateful update script with the correct args.
152 """
153 self.mox.StubOutWithMock(autoupdater.ChromiumOSUpdater, '_run')
Chris Sosab9ada9b2013-06-12 12:47:47 -0700154 self.mox.StubOutWithMock(autoupdater.ChromiumOSUpdater,
Richard Barnettef00a2ee2018-06-08 11:51:38 -0700155 '_get_stateful_update_script')
Chris Sosa72312602013-04-16 15:01:56 -0700156 update_url = ('http://172.22.50.205:8082/update/lumpy-chrome-perf/'
157 'R28-4444.0.0-b2996')
joychen03eaad92013-06-26 09:55:21 -0700158 static_update_url = ('http://172.22.50.205:8082/static/'
Chris Sosa72312602013-04-16 15:01:56 -0700159 'lumpy-chrome-perf/R28-4444.0.0-b2996')
Richard Barnettef00a2ee2018-06-08 11:51:38 -0700160 update_script = '/usr/local/bin/stateful_update'
Chris Sosa72312602013-04-16 15:01:56 -0700161
162 # Test with clobber=False.
Richard Barnettef00a2ee2018-06-08 11:51:38 -0700163 autoupdater.ChromiumOSUpdater._get_stateful_update_script().AndReturn(
164 update_script)
Chris Sosa72312602013-04-16 15:01:56 -0700165 autoupdater.ChromiumOSUpdater._run(
166 mox.And(
Richard Barnettef00a2ee2018-06-08 11:51:38 -0700167 mox.StrContains(update_script),
Chris Sosa72312602013-04-16 15:01:56 -0700168 mox.StrContains(static_update_url),
169 mox.Not(mox.StrContains('--stateful_change=clean'))),
Dan Shi80aa9102016-01-25 13:45:00 -0800170 timeout=mox.IgnoreArg())
Chris Sosa72312602013-04-16 15:01:56 -0700171
172 self.mox.ReplayAll()
173 updater = autoupdater.ChromiumOSUpdater(update_url)
174 updater.update_stateful(clobber=False)
175 self.mox.VerifyAll()
176
177 # Test with clobber=True.
178 self.mox.ResetAll()
Richard Barnettef00a2ee2018-06-08 11:51:38 -0700179 autoupdater.ChromiumOSUpdater._get_stateful_update_script().AndReturn(
180 update_script)
Chris Sosa72312602013-04-16 15:01:56 -0700181 autoupdater.ChromiumOSUpdater._run(
182 mox.And(
Richard Barnettef00a2ee2018-06-08 11:51:38 -0700183 mox.StrContains(update_script),
Chris Sosa72312602013-04-16 15:01:56 -0700184 mox.StrContains(static_update_url),
185 mox.StrContains('--stateful_change=clean')),
Dan Shi80aa9102016-01-25 13:45:00 -0800186 timeout=mox.IgnoreArg())
Chris Sosa72312602013-04-16 15:01:56 -0700187 self.mox.ReplayAll()
188 updater = autoupdater.ChromiumOSUpdater(update_url)
189 updater.update_stateful(clobber=True)
190 self.mox.VerifyAll()
191
192
Richard Barnettef00a2ee2018-06-08 11:51:38 -0700193 def testGetRemoteScript(self):
194 """Test _get_remote_script() behaviors."""
Gwendal Grignou3e96cc22017-06-07 16:22:51 -0700195 update_url = ('http://172.22.50.205:8082/update/lumpy-chrome-perf/'
196 'R28-4444.0.0-b2996')
Richard Barnettef00a2ee2018-06-08 11:51:38 -0700197 script_name = 'fubar'
198 local_script = '/usr/local/bin/%s' % script_name
Gwendal Grignou3e96cc22017-06-07 16:22:51 -0700199 host = self.mox.CreateMockAnything()
200 updater = autoupdater.ChromiumOSUpdater(update_url, host=host)
Richard Barnettef00a2ee2018-06-08 11:51:38 -0700201 host.path_exists(local_script).AndReturn(True)
Gwendal Grignou3e96cc22017-06-07 16:22:51 -0700202
203 self.mox.ReplayAll()
Richard Barnettef00a2ee2018-06-08 11:51:38 -0700204 # Simple case: file exists on DUT
205 self.assertEqual(updater._get_remote_script(script_name),
206 local_script)
Gwendal Grignou3e96cc22017-06-07 16:22:51 -0700207 self.mox.VerifyAll()
208
Gwendal Grignou3e96cc22017-06-07 16:22:51 -0700209 self.mox.ResetAll()
Richard Barnettef00a2ee2018-06-08 11:51:38 -0700210 fake_shell = '/bin/ash'
211 tmp_script = '/tmp/%s' % script_name
212 fake_result = self.mox.CreateMockAnything()
213 fake_result.stdout = ' %s\n' % fake_shell
214 host.path_exists(local_script).AndReturn(False)
215 host.run(mox.IgnoreArg(),
216 ignore_status=True).AndReturn(fake_result)
217
Gwendal Grignou3e96cc22017-06-07 16:22:51 -0700218 self.mox.ReplayAll()
Richard Barnettef00a2ee2018-06-08 11:51:38 -0700219 # Complicated case: script not on DUT, so try to download it.
Gwendal Grignou3e96cc22017-06-07 16:22:51 -0700220 self.assertEqual(
Richard Barnettef00a2ee2018-06-08 11:51:38 -0700221 updater._get_remote_script(script_name),
222 '%s %s' % (fake_shell, tmp_script))
Gwendal Grignou3e96cc22017-06-07 16:22:51 -0700223 self.mox.VerifyAll()
224
225
Chris Sosac8617522014-06-09 23:22:26 +0000226 def testRollbackRootfs(self):
227 """Tests that we correctly rollback the rootfs when requested."""
228 self.mox.StubOutWithMock(autoupdater.ChromiumOSUpdater, '_run')
Chris Sosac8617522014-06-09 23:22:26 +0000229 self.mox.StubOutWithMock(autoupdater.ChromiumOSUpdater,
230 '_verify_update_completed')
231 host = self.mox.CreateMockAnything()
232 update_url = 'http://server/test/url'
233 host.hostname = 'test_host'
234
235 can_rollback_cmd = ('/usr/bin/update_engine_client --can_rollback')
236 rollback_cmd = ('/usr/bin/update_engine_client --rollback '
237 '--follow')
238
239 updater = autoupdater.ChromiumOSUpdater(update_url, host=host)
240
241 # Return an old build which shouldn't call can_rollback.
Dan Shi549fb822015-03-24 18:01:11 -0700242 updater.host.get_release_version().AndReturn('1234.0.0')
Chris Sosac8617522014-06-09 23:22:26 +0000243 autoupdater.ChromiumOSUpdater._run(rollback_cmd)
244 autoupdater.ChromiumOSUpdater._verify_update_completed()
245
246 self.mox.ReplayAll()
247 updater.rollback_rootfs(powerwash=True)
248 self.mox.VerifyAll()
249
250 self.mox.ResetAll()
251 cmd_result_1 = self.mox.CreateMockAnything()
252 cmd_result_1.exit_status = 1
253
254 # Rollback but can_rollback says we can't -- return an error.
Dan Shi549fb822015-03-24 18:01:11 -0700255 updater.host.get_release_version().AndReturn('5775.0.0')
Chris Sosac8617522014-06-09 23:22:26 +0000256 autoupdater.ChromiumOSUpdater._run(can_rollback_cmd).AndRaise(
257 error.AutoservRunError('can_rollback failed', cmd_result_1))
258 self.mox.ReplayAll()
259 self.assertRaises(autoupdater.RootFSUpdateError,
260 updater.rollback_rootfs, True)
261 self.mox.VerifyAll()
262
263 self.mox.ResetAll()
264 # Rollback >= version blacklisted.
Dan Shi549fb822015-03-24 18:01:11 -0700265 updater.host.get_release_version().AndReturn('5775.0.0')
Chris Sosac8617522014-06-09 23:22:26 +0000266 autoupdater.ChromiumOSUpdater._run(can_rollback_cmd)
267 autoupdater.ChromiumOSUpdater._run(rollback_cmd)
268 autoupdater.ChromiumOSUpdater._verify_update_completed()
269 self.mox.ReplayAll()
270 updater.rollback_rootfs(powerwash=True)
271 self.mox.VerifyAll()
272
273
Scott Zawalskieadbf702013-03-14 09:23:06 -0400274if __name__ == '__main__':
275 unittest.main()