blob: d02688dd687b78359823faf667d34191ccaf7200 [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
Gwendal Grignou3e96cc22017-06-07 16:22:51 -07007import os
Scott Zawalskieadbf702013-03-14 09:23:06 -04008import unittest
9
10import common
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -080011import time
Scott Zawalskieadbf702013-03-14 09:23:06 -040012
13import autoupdater
Don Garrettdf8aef72013-12-16 11:12:41 -080014from autotest_lib.client.common_lib import error
Gwendal Grignou3e96cc22017-06-07 16:22:51 -070015from autotest_lib.client.common_lib.test_utils import mock
Scott Zawalskieadbf702013-03-14 09:23:06 -040016
Dan Shib95bb862013-03-22 16:29:28 -070017class TestAutoUpdater(mox.MoxTestBase):
Scott Zawalskieadbf702013-03-14 09:23:06 -040018 """Test autoupdater module."""
19
20
21 def testParseBuildFromUpdateUrlwithUpdate(self):
22 """Test that we properly parse the build from an update_url."""
23 update_url = ('http://172.22.50.205:8082/update/lumpy-release/'
24 'R27-3837.0.0')
25 expected_value = 'lumpy-release/R27-3837.0.0'
26 self.assertEqual(autoupdater.url_to_image_name(update_url),
27 expected_value)
28
29
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -080030 def _host_run_for_update(self, cmd, exception=None,
31 bad_update_status=False):
32 """Helper function for AU tests.
33
34 @param host: the test host
35 @param cmd: the command to be recorded
36 @param exception: the exception to be recorded, or None
37 """
38 if exception:
39 self.host.run(command=cmd).AndRaise(exception)
40 else:
41 result = self.mox.CreateMockAnything()
42 if bad_update_status:
43 # Pick randomly one unexpected status
44 result.stdout = 'UPDATE_STATUS_UPDATED_NEED_REBOOT'
45 else:
46 result.stdout = 'UPDATE_STATUS_IDLE'
47 result.status = 0
48 self.host.run(command=cmd).AndReturn(result)
49
50
Don Garrettdf8aef72013-12-16 11:12:41 -080051 def testTriggerUpdate(self):
52 """Tests that we correctly handle updater errors."""
Don Garrettdf8aef72013-12-16 11:12:41 -080053 update_url = 'http://server/test/url'
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -080054 self.host = self.mox.CreateMockAnything()
55 self.mox.StubOutWithMock(self.host, 'run')
Shuqian Zhaod9992722016-02-29 12:26:38 -080056 self.mox.StubOutWithMock(autoupdater.ChromiumOSUpdater,
Richard Barnette3e8b2282018-05-15 20:42:20 +000057 '_get_last_update_error')
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -080058 self.host.hostname = 'test_host'
59 updater_control_bin = '/usr/bin/update_engine_client'
60 test_url = 'http://server/test/url'
61 expected_wait_cmd = ('%s -status | grep CURRENT_OP' %
62 updater_control_bin)
63 expected_cmd = ('%s --check_for_update --omaha_url=%s' %
64 (updater_control_bin, test_url))
65 self.mox.StubOutWithMock(time, "sleep")
66 UPDATE_ENGINE_RETRY_WAIT_TIME=5
Don Garrettdf8aef72013-12-16 11:12:41 -080067
Luigi Semenzatoe76d9f82016-11-21 11:15:10 -080068 # Generic SSH Error.
Don Garrettdf8aef72013-12-16 11:12:41 -080069 cmd_result_255 = self.mox.CreateMockAnything()
70 cmd_result_255.exit_status = 255
71
Shuqian Zhaod9992722016-02-29 12:26:38 -080072 # Command Failed Error
73 cmd_result_1 = self.mox.CreateMockAnything()
74 cmd_result_1.exit_status = 1
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -080075
76 # Error 37
77 cmd_result_37 = self.mox.CreateMockAnything()
78 cmd_result_37.exit_status = 37
79
80 updater = autoupdater.ChromiumOSUpdater(update_url, host=self.host)
81
82 # (SUCCESS) Expect one wait command and one status command.
83 self._host_run_for_update(expected_wait_cmd)
84 self._host_run_for_update(expected_cmd)
85
86 # (SUCCESS) Test with one retry to wait for update-engine.
87 self._host_run_for_update(expected_wait_cmd, exception=
88 error.AutoservRunError('non-zero status', cmd_result_1))
89 time.sleep(UPDATE_ENGINE_RETRY_WAIT_TIME)
90 self._host_run_for_update(expected_wait_cmd)
91 self._host_run_for_update(expected_cmd)
92
93 # (SUCCESS) One-time SSH timeout, then success on retry.
94 self._host_run_for_update(expected_wait_cmd)
95 self._host_run_for_update(expected_cmd, exception=
96 error.AutoservSSHTimeout('ssh timed out', cmd_result_255))
97 self._host_run_for_update(expected_cmd)
98
99 # (SUCCESS) One-time ERROR 37, then success.
100 self._host_run_for_update(expected_wait_cmd)
101 self._host_run_for_update(expected_cmd, exception=
102 error.AutoservRunError('ERROR_CODE=37', cmd_result_37))
103 self._host_run_for_update(expected_cmd)
104
105 # (FAILURE) Bad status of update engine.
106 self._host_run_for_update(expected_wait_cmd)
107 self._host_run_for_update(expected_cmd, bad_update_status=True,
108 exception=error.InstallError(
109 'host is not in installable state'))
110
111 # (FAILURE) Two-time SSH timeout.
112 self._host_run_for_update(expected_wait_cmd)
113 self._host_run_for_update(expected_cmd, exception=
114 error.AutoservSSHTimeout('ssh timed out', cmd_result_255))
115 self._host_run_for_update(expected_cmd, exception=
116 error.AutoservSSHTimeout('ssh timed out', cmd_result_255))
117
118 # (FAILURE) SSH Permission Error
119 self._host_run_for_update(expected_wait_cmd)
120 self._host_run_for_update(expected_cmd, exception=
121 error.AutoservSshPermissionDeniedError('no permission',
122 cmd_result_255))
123
124 # (FAILURE) Other ssh failure
125 self._host_run_for_update(expected_wait_cmd)
126 self._host_run_for_update(expected_cmd, exception=
127 error.AutoservSshPermissionDeniedError('no permission',
128 cmd_result_255))
129 # (FAILURE) Other error
130 self._host_run_for_update(expected_wait_cmd)
131 self._host_run_for_update(expected_cmd, exception=
Luigi Semenzatoe76d9f82016-11-21 11:15:10 -0800132 error.AutoservRunError("unknown error", cmd_result_1))
Shuqian Zhaod9992722016-02-29 12:26:38 -0800133
Don Garrettdf8aef72013-12-16 11:12:41 -0800134 self.mox.ReplayAll()
135
Luigi Semenzatoe76d9f82016-11-21 11:15:10 -0800136 # Expect success
137 updater.trigger_update()
138 updater.trigger_update()
Don Garrettdf8aef72013-12-16 11:12:41 -0800139 updater.trigger_update()
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -0800140 updater.trigger_update()
Don Garrettdf8aef72013-12-16 11:12:41 -0800141
Luigi Semenzatoe76d9f82016-11-21 11:15:10 -0800142 # Expect errors as listed above
143 self.assertRaises(autoupdater.RootFSUpdateError, updater.trigger_update)
144 self.assertRaises(autoupdater.RootFSUpdateError, updater.trigger_update)
145 self.assertRaises(autoupdater.RootFSUpdateError, updater.trigger_update)
146 self.assertRaises(autoupdater.RootFSUpdateError, updater.trigger_update)
Luigi Semenzatof15c8fc2017-03-03 14:12:40 -0800147 self.assertRaises(autoupdater.RootFSUpdateError, updater.trigger_update)
Don Garrettdf8aef72013-12-16 11:12:41 -0800148
149 self.mox.VerifyAll()
150
151
Chris Sosa72312602013-04-16 15:01:56 -0700152 def testUpdateStateful(self):
153 """Tests that we call the stateful update script with the correct args.
154 """
155 self.mox.StubOutWithMock(autoupdater.ChromiumOSUpdater, '_run')
Chris Sosab9ada9b2013-06-12 12:47:47 -0700156 self.mox.StubOutWithMock(autoupdater.ChromiumOSUpdater,
157 'get_stateful_update_script')
Chris Sosa72312602013-04-16 15:01:56 -0700158 update_url = ('http://172.22.50.205:8082/update/lumpy-chrome-perf/'
159 'R28-4444.0.0-b2996')
joychen03eaad92013-06-26 09:55:21 -0700160 static_update_url = ('http://172.22.50.205:8082/static/'
Chris Sosa72312602013-04-16 15:01:56 -0700161 'lumpy-chrome-perf/R28-4444.0.0-b2996')
162
163 # Test with clobber=False.
Chris Sosab9ada9b2013-06-12 12:47:47 -0700164 autoupdater.ChromiumOSUpdater.get_stateful_update_script().AndReturn(
Richard Barnette3e8b2282018-05-15 20:42:20 +0000165 autoupdater._REMOTE_STATEFUL_UPDATE_PATH)
Chris Sosa72312602013-04-16 15:01:56 -0700166 autoupdater.ChromiumOSUpdater._run(
167 mox.And(
Gilad Arnold0c0df732015-09-21 06:37:59 -0700168 mox.StrContains(
Richard Barnette3e8b2282018-05-15 20:42:20 +0000169 autoupdater._REMOTE_STATEFUL_UPDATE_PATH),
Chris Sosa72312602013-04-16 15:01:56 -0700170 mox.StrContains(static_update_url),
171 mox.Not(mox.StrContains('--stateful_change=clean'))),
Dan Shi80aa9102016-01-25 13:45:00 -0800172 timeout=mox.IgnoreArg())
Chris Sosa72312602013-04-16 15:01:56 -0700173
174 self.mox.ReplayAll()
175 updater = autoupdater.ChromiumOSUpdater(update_url)
176 updater.update_stateful(clobber=False)
177 self.mox.VerifyAll()
178
179 # Test with clobber=True.
180 self.mox.ResetAll()
Chris Sosab9ada9b2013-06-12 12:47:47 -0700181 autoupdater.ChromiumOSUpdater.get_stateful_update_script().AndReturn(
Richard Barnette3e8b2282018-05-15 20:42:20 +0000182 autoupdater._REMOTE_STATEFUL_UPDATE_PATH)
Chris Sosa72312602013-04-16 15:01:56 -0700183 autoupdater.ChromiumOSUpdater._run(
184 mox.And(
Gilad Arnold0c0df732015-09-21 06:37:59 -0700185 mox.StrContains(
Richard Barnette3e8b2282018-05-15 20:42:20 +0000186 autoupdater._REMOTE_STATEFUL_UPDATE_PATH),
Chris Sosa72312602013-04-16 15:01:56 -0700187 mox.StrContains(static_update_url),
188 mox.StrContains('--stateful_change=clean')),
Dan Shi80aa9102016-01-25 13:45:00 -0800189 timeout=mox.IgnoreArg())
Chris Sosa72312602013-04-16 15:01:56 -0700190 self.mox.ReplayAll()
191 updater = autoupdater.ChromiumOSUpdater(update_url)
192 updater.update_stateful(clobber=True)
193 self.mox.VerifyAll()
194
195
Gwendal Grignou3e96cc22017-06-07 16:22:51 -0700196 def testGetStatefulUpdateScript(self):
197 """ Test that get_stateful_update_script look for stateful_update.
198
199 Check get_stateful_update_script is trying hard to find
200 stateful_update and assert if it can't.
201
202 """
203 update_url = ('http://172.22.50.205:8082/update/lumpy-chrome-perf/'
204 'R28-4444.0.0-b2996')
Richard Barnette3e8b2282018-05-15 20:42:20 +0000205 script_loc = os.path.join(autoupdater._STATEFUL_UPDATE_PATH,
206 autoupdater._STATEFUL_UPDATE_SCRIPT)
Gwendal Grignou3e96cc22017-06-07 16:22:51 -0700207 self.god = mock.mock_god()
208 self.god.stub_function(os.path, 'exists')
209 host = self.mox.CreateMockAnything()
210 updater = autoupdater.ChromiumOSUpdater(update_url, host=host)
211 os.path.exists.expect_call(script_loc).and_return(False)
212 host.path_exists('/usr/local/bin/stateful_update').AndReturn(False)
213
214 self.mox.ReplayAll()
215 # No existing files, no URL, we should assert.
216 self.assertRaises(
Richard Barnette9d43e562018-06-05 17:20:10 +0000217 autoupdater.StatefulUpdateError,
Gwendal Grignou3e96cc22017-06-07 16:22:51 -0700218 updater.get_stateful_update_script)
219 self.mox.VerifyAll()
220
221 # No existing files, but stateful URL, we will try.
222 self.mox.ResetAll()
223 os.path.exists.expect_call(script_loc).and_return(True)
224 host.send_file(
225 script_loc,
226 '/tmp/stateful_update', delete_dest=True).AndReturn(True)
227 self.mox.ReplayAll()
228 self.assertEqual(
229 updater.get_stateful_update_script(),
230 '/tmp/stateful_update')
231 self.mox.VerifyAll()
232
233
Chris Sosac8617522014-06-09 23:22:26 +0000234 def testRollbackRootfs(self):
235 """Tests that we correctly rollback the rootfs when requested."""
236 self.mox.StubOutWithMock(autoupdater.ChromiumOSUpdater, '_run')
Chris Sosac8617522014-06-09 23:22:26 +0000237 self.mox.StubOutWithMock(autoupdater.ChromiumOSUpdater,
238 '_verify_update_completed')
239 host = self.mox.CreateMockAnything()
240 update_url = 'http://server/test/url'
241 host.hostname = 'test_host'
242
243 can_rollback_cmd = ('/usr/bin/update_engine_client --can_rollback')
244 rollback_cmd = ('/usr/bin/update_engine_client --rollback '
245 '--follow')
246
247 updater = autoupdater.ChromiumOSUpdater(update_url, host=host)
248
249 # Return an old build which shouldn't call can_rollback.
Dan Shi549fb822015-03-24 18:01:11 -0700250 updater.host.get_release_version().AndReturn('1234.0.0')
Chris Sosac8617522014-06-09 23:22:26 +0000251 autoupdater.ChromiumOSUpdater._run(rollback_cmd)
252 autoupdater.ChromiumOSUpdater._verify_update_completed()
253
254 self.mox.ReplayAll()
255 updater.rollback_rootfs(powerwash=True)
256 self.mox.VerifyAll()
257
258 self.mox.ResetAll()
259 cmd_result_1 = self.mox.CreateMockAnything()
260 cmd_result_1.exit_status = 1
261
262 # Rollback but can_rollback says we can't -- return an error.
Dan Shi549fb822015-03-24 18:01:11 -0700263 updater.host.get_release_version().AndReturn('5775.0.0')
Chris Sosac8617522014-06-09 23:22:26 +0000264 autoupdater.ChromiumOSUpdater._run(can_rollback_cmd).AndRaise(
265 error.AutoservRunError('can_rollback failed', cmd_result_1))
266 self.mox.ReplayAll()
267 self.assertRaises(autoupdater.RootFSUpdateError,
268 updater.rollback_rootfs, True)
269 self.mox.VerifyAll()
270
271 self.mox.ResetAll()
272 # Rollback >= version blacklisted.
Dan Shi549fb822015-03-24 18:01:11 -0700273 updater.host.get_release_version().AndReturn('5775.0.0')
Chris Sosac8617522014-06-09 23:22:26 +0000274 autoupdater.ChromiumOSUpdater._run(can_rollback_cmd)
275 autoupdater.ChromiumOSUpdater._run(rollback_cmd)
276 autoupdater.ChromiumOSUpdater._verify_update_completed()
277 self.mox.ReplayAll()
278 updater.rollback_rootfs(powerwash=True)
279 self.mox.VerifyAll()
280
281
Scott Zawalskieadbf702013-03-14 09:23:06 -0400282if __name__ == '__main__':
283 unittest.main()