blob: 6d31fa9b97f520331ee790e64670fad93e73cad0 [file] [log] [blame]
Alex Klein2966e302019-01-17 13:29:38 -07001# Copyright 2019 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.
4
5"""Image service tests."""
6
Alex Klein2966e302019-01-17 13:29:38 -07007import os
Joseph Sussman34c01be2022-06-03 14:04:41 +00008from pathlib import Path
Mike Frysinger166fea02021-02-12 05:30:33 -05009from unittest import mock
Alex Klein2966e302019-01-17 13:29:38 -070010
Alex Klein231d2da2019-07-22 16:44:45 -060011from chromite.api import api_config
Alex Klein8cb365a2019-05-15 16:24:53 -060012from chromite.api import controller
13from chromite.api.controller import image as image_controller
Alex Klein7107bdd2019-03-14 17:14:31 -060014from chromite.api.gen.chromite.api import image_pb2
Jack Neus761e1842020-12-01 18:20:11 +000015from chromite.api.gen.chromite.api import sysroot_pb2
Mike Frysinger1cc8f1f2022-04-28 22:40:40 -040016from chromite.api.gen.chromiumos import common_pb2
Alex Klein56355682019-02-07 10:36:54 -070017from chromite.lib import constants
Alex Klein4f0eb432019-05-02 13:56:04 -060018from chromite.lib import cros_build_lib
Alex Klein2966e302019-01-17 13:29:38 -070019from chromite.lib import cros_test_lib
Michael Mortensenc83c9952019-08-05 12:15:12 -060020from chromite.lib import image_lib
Alex Klein2966e302019-01-17 13:29:38 -070021from chromite.lib import osutils
Jack Neus761e1842020-12-01 18:20:11 +000022from chromite.scripts import pushimage
Alex Kleinb7cdbe62019-02-22 11:41:32 -070023from chromite.service import image as image_service
Alex Klein2966e302019-01-17 13:29:38 -070024
25
Alex Klein231d2da2019-07-22 16:44:45 -060026class CreateTest(cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin):
Alex Klein56355682019-02-07 10:36:54 -070027 """Create image tests."""
28
Alex Klein231d2da2019-07-22 16:44:45 -060029 def setUp(self):
30 self.response = image_pb2.CreateImageResult()
31
Jack Neus761e1842020-12-01 18:20:11 +000032 def _GetRequest(self,
33 board=None,
34 types=None,
35 version=None,
36 builder_path=None,
Joseph Sussman34c01be2022-06-03 14:04:41 +000037 disable_rootfs_verification=False,
38 base_is_recovery=False):
Alex Klein21b95022019-05-09 14:14:46 -060039 """Helper to build a request instance."""
40 return image_pb2.CreateImageRequest(
41 build_target={'name': board},
42 image_types=types,
43 disable_rootfs_verification=disable_rootfs_verification,
44 version=version,
45 builder_path=builder_path,
Joseph Sussman34c01be2022-06-03 14:04:41 +000046 base_is_recovery=base_is_recovery,
Alex Klein21b95022019-05-09 14:14:46 -060047 )
48
Alex Klein231d2da2019-07-22 16:44:45 -060049 def testValidateOnly(self):
50 """Sanity check that a validate only call does not execute any logic."""
51 patch = self.PatchObject(image_service, 'Build')
Alex Klein21b95022019-05-09 14:14:46 -060052
Alex Klein231d2da2019-07-22 16:44:45 -060053 request = self._GetRequest(board='board')
54 image_controller.Create(request, self.response, self.validate_only_config)
55 patch.assert_not_called()
56
Michael Mortensen10146cf2019-11-19 19:59:22 -070057 def testMockCall(self):
58 """Test that mock call does not execute any logic, returns mocked value."""
59 patch = self.PatchObject(image_service, 'Build')
60
61 request = self._GetRequest(board='board')
62 image_controller.Create(request, self.response, self.mock_call_config)
63 patch.assert_not_called()
64 self.assertEqual(self.response.success, True)
65
Michael Mortensen85d38402019-12-12 09:50:29 -070066 def testMockError(self):
67 """Test that mock call does not execute any logic, returns error."""
68 patch = self.PatchObject(image_service, 'Build')
69
70 request = self._GetRequest(board='board')
71 rc = image_controller.Create(request, self.response, self.mock_error_config)
72 patch.assert_not_called()
73 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
74
Alex Klein231d2da2019-07-22 16:44:45 -060075 def testNoBoard(self):
76 """Test no board given fails."""
77 request = self._GetRequest()
Alex Klein56355682019-02-07 10:36:54 -070078
79 # No board should cause it to fail.
Alex Klein4f0eb432019-05-02 13:56:04 -060080 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060081 image_controller.Create(request, self.response, self.api_config)
Alex Klein56355682019-02-07 10:36:54 -070082
Alex Klein21b95022019-05-09 14:14:46 -060083 def testNoTypeSpecified(self):
84 """Test the image type default."""
85 request = self._GetRequest(board='board')
Alex Klein21b95022019-05-09 14:14:46 -060086
Alex Klein1bcd9882019-03-19 13:25:24 -060087 # Failed result to avoid the success handling logic.
Alex Klein27978a42021-07-27 14:18:10 -060088 result = image_service.BuildResult([constants.IMAGE_TYPE_BASE])
89 result.return_code = 1
Alex Klein1bcd9882019-03-19 13:25:24 -060090 build_patch = self.PatchObject(image_service, 'Build', return_value=result)
Alex Klein56355682019-02-07 10:36:54 -070091
Alex Klein231d2da2019-07-22 16:44:45 -060092 image_controller.Create(request, self.response, self.api_config)
Alex Klein27978a42021-07-27 14:18:10 -060093 build_patch.assert_any_call(
94 'board', [constants.IMAGE_TYPE_BASE], config=mock.ANY)
Alex Klein56355682019-02-07 10:36:54 -070095
Alex Klein21b95022019-05-09 14:14:46 -060096 def testSingleTypeSpecified(self):
97 """Test it's properly using a specified type."""
George Engelbrechtc55d6312021-05-05 12:11:13 -060098 request = self._GetRequest(board='board', types=[common_pb2.IMAGE_TYPE_DEV])
Alex Klein21b95022019-05-09 14:14:46 -060099
100 # Failed result to avoid the success handling logic.
Alex Klein27978a42021-07-27 14:18:10 -0600101 result = image_service.BuildResult([constants.IMAGE_TYPE_DEV])
102 result.return_code = 1
Alex Klein21b95022019-05-09 14:14:46 -0600103 build_patch = self.PatchObject(image_service, 'Build', return_value=result)
104
Alex Klein231d2da2019-07-22 16:44:45 -0600105 image_controller.Create(request, self.response, self.api_config)
Alex Klein27978a42021-07-27 14:18:10 -0600106 build_patch.assert_any_call(
107 'board', [constants.IMAGE_TYPE_DEV], config=mock.ANY)
Alex Klein56355682019-02-07 10:36:54 -0700108
Alex Klein21b95022019-05-09 14:14:46 -0600109 def testMultipleAndImpliedTypes(self):
110 """Test multiple types and implied type handling."""
111 # The TEST_VM type should force it to build the test image.
George Engelbrechtc55d6312021-05-05 12:11:13 -0600112 types = [common_pb2.IMAGE_TYPE_BASE, common_pb2.IMAGE_TYPE_TEST_VM]
Alex Klein21b95022019-05-09 14:14:46 -0600113 expected_images = [constants.IMAGE_TYPE_BASE, constants.IMAGE_TYPE_TEST]
114
115 request = self._GetRequest(board='board', types=types)
Alex Klein21b95022019-05-09 14:14:46 -0600116
117 # Failed result to avoid the success handling logic.
Alex Klein27978a42021-07-27 14:18:10 -0600118 result = image_service.BuildResult(expected_images)
119 result.return_code = 1
Alex Klein21b95022019-05-09 14:14:46 -0600120 build_patch = self.PatchObject(image_service, 'Build', return_value=result)
121
Alex Klein231d2da2019-07-22 16:44:45 -0600122 image_controller.Create(request, self.response, self.api_config)
Alex Klein27978a42021-07-27 14:18:10 -0600123 build_patch.assert_any_call('board', expected_images, config=mock.ANY)
Alex Klein56355682019-02-07 10:36:54 -0700124
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700125 def testRecoveryImpliedTypes(self):
126 """Test implied type handling of recovery images."""
127 # The TEST_VM type should force it to build the test image.
128 types = [common_pb2.IMAGE_TYPE_RECOVERY]
129
130 request = self._GetRequest(board='board', types=types)
131
132 # Failed result to avoid the success handling logic.
Alex Klein27978a42021-07-27 14:18:10 -0600133 result = image_service.BuildResult([])
134 result.return_code = 1
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700135 build_patch = self.PatchObject(image_service, 'Build', return_value=result)
136
137 image_controller.Create(request, self.response, self.api_config)
Alex Klein27978a42021-07-27 14:18:10 -0600138 build_patch.assert_any_call(
139 'board', [constants.IMAGE_TYPE_BASE], config=mock.ANY)
George Engelbrecht9f4f8322021-03-08 12:04:17 -0700140
Alex Klein1bcd9882019-03-19 13:25:24 -0600141 def testFailedPackageHandling(self):
142 """Test failed packages are populated correctly."""
Alex Klein27978a42021-07-27 14:18:10 -0600143 result = image_service.BuildResult([])
144 result.return_code = 1
145 result.failed_packages = ['foo/bar', 'cat/pkg']
Alex Klein1bcd9882019-03-19 13:25:24 -0600146 expected_packages = [('foo', 'bar'), ('cat', 'pkg')]
147 self.PatchObject(image_service, 'Build', return_value=result)
148
Alex Klein231d2da2019-07-22 16:44:45 -0600149 input_proto = self._GetRequest(board='board')
Alex Klein1bcd9882019-03-19 13:25:24 -0600150
Alex Klein231d2da2019-07-22 16:44:45 -0600151 rc = image_controller.Create(input_proto, self.response, self.api_config)
152
Alex Klein8cb365a2019-05-15 16:24:53 -0600153 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Klein231d2da2019-07-22 16:44:45 -0600154 for package in self.response.failed_packages:
Alex Klein1bcd9882019-03-19 13:25:24 -0600155 self.assertIn((package.category, package.package_name), expected_packages)
156
Alex Klein2557b4f2019-07-11 14:34:00 -0600157 def testNoPackagesFailureHandling(self):
158 """Test failed packages are populated correctly."""
Alex Klein27978a42021-07-27 14:18:10 -0600159 result = image_service.BuildResult([])
160 result.return_code = 1
Alex Klein2557b4f2019-07-11 14:34:00 -0600161 self.PatchObject(image_service, 'Build', return_value=result)
Alex Kleinb7cdbe62019-02-22 11:41:32 -0700162
Alex Klein2557b4f2019-07-11 14:34:00 -0600163 input_proto = image_pb2.CreateImageRequest()
164 input_proto.build_target.name = 'board'
Alex Klein2557b4f2019-07-11 14:34:00 -0600165
Alex Klein231d2da2019-07-22 16:44:45 -0600166 rc = image_controller.Create(input_proto, self.response, self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600167 self.assertTrue(rc)
168 self.assertNotEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE,
169 rc)
Alex Klein231d2da2019-07-22 16:44:45 -0600170 self.assertFalse(self.response.failed_packages)
Alex Klein2557b4f2019-07-11 14:34:00 -0600171
Joseph Sussman34c01be2022-06-03 14:04:41 +0000172 def testBaseIsRecoveryTrue(self):
173 """Test that cp is called."""
174 types = [common_pb2.IMAGE_TYPE_BASE,
175 common_pb2.IMAGE_TYPE_RECOVERY]
176 input_proto = self._GetRequest(board='board', types=types,
177 base_is_recovery=True)
178 # Images must exist to be added to the result.
179 self.PatchObject(Path, 'exists', return_value=True)
180 rc_mock = cros_test_lib.RunCommandMock()
181 rc_mock.SetDefaultCmdResult(returncode=0)
182 with rc_mock:
183 image_controller.Create(input_proto, self.response, self.api_config)
184 rc_mock.assertCommandContains(['cp', mock.ANY, mock.ANY])
185
186 def testBaseIsRecoveryFalse(self):
187 """Test that mod_image_for_recovery.sh is called."""
188 types = [common_pb2.IMAGE_TYPE_BASE,
189 common_pb2.IMAGE_TYPE_RECOVERY]
190 input_proto = self._GetRequest(board='board', types=types,
191 base_is_recovery=False)
192 self.PatchObject(Path, 'exists', return_value=True)
193 rc_mock = cros_test_lib.RunCommandMock()
194 rc_mock.SetDefaultCmdResult(returncode=0)
195 with rc_mock:
196 image_controller.Create(input_proto, self.response, self.api_config)
197 mod_script = os.path.join(constants.CROSUTILS_DIR,
198 'mod_image_for_recovery.sh')
199 rc_mock.assertCommandContains([mod_script, '--board', 'board', mock.ANY])
200
Alex Klein2557b4f2019-07-11 14:34:00 -0600201
Alex Klein231d2da2019-07-22 16:44:45 -0600202class ImageSignerTestTest(cros_test_lib.MockTempDirTestCase,
203 api_config.ApiConfigMixin):
Michael Mortensenc83c9952019-08-05 12:15:12 -0600204 """Image signer test tests."""
205
206 def setUp(self):
207 self.image_path = os.path.join(self.tempdir, 'image.bin')
Michael Mortensenc83c9952019-08-05 12:15:12 -0600208 self.result_directory = os.path.join(self.tempdir, 'results')
209
210 osutils.SafeMakedirs(self.result_directory)
211 osutils.Touch(self.image_path)
212
Alex Klein231d2da2019-07-22 16:44:45 -0600213 def testValidateOnly(self):
214 """Sanity check that validate-only calls don't execute any logic."""
215 patch = self.PatchObject(image_lib, 'SecurityTest', return_value=True)
216 input_proto = image_pb2.TestImageRequest()
217 input_proto.image.path = self.image_path
218 output_proto = image_pb2.TestImageResult()
219
220 image_controller.SignerTest(input_proto, output_proto,
221 self.validate_only_config)
222
223 patch.assert_not_called()
224
Michael Mortensen10146cf2019-11-19 19:59:22 -0700225 def testMockCall(self):
226 """Test that mock call does not execute any logic, returns mocked value."""
227 patch = self.PatchObject(image_lib, 'SecurityTest', return_value=True)
228 input_proto = image_pb2.TestImageRequest()
229 input_proto.image.path = self.image_path
230 output_proto = image_pb2.TestImageResult()
231
232 image_controller.SignerTest(input_proto, output_proto,
233 self.mock_call_config)
234
235 patch.assert_not_called()
236 self.assertEqual(output_proto.success, True)
237
Michael Mortensen85d38402019-12-12 09:50:29 -0700238 def testMockError(self):
239 """Test that mock call does not execute any logic, returns error."""
240 patch = self.PatchObject(image_lib, 'SecurityTest', return_value=True)
241 input_proto = image_pb2.TestImageRequest()
242 input_proto.image.path = self.image_path
243 output_proto = image_pb2.TestImageResult()
244
245 rc = image_controller.SignerTest(input_proto, output_proto,
246 self.mock_error_config)
247
248 patch.assert_not_called()
249 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
250
Alex Klein231d2da2019-07-22 16:44:45 -0600251 def testSignerTestNoImage(self):
252 """Test function argument validation."""
Michael Mortensenc83c9952019-08-05 12:15:12 -0600253 input_proto = image_pb2.TestImageRequest()
254 output_proto = image_pb2.TestImageResult()
255
256 # Nothing provided.
257 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600258 image_controller.SignerTest(input_proto, output_proto, self.api_config)
Michael Mortensenc83c9952019-08-05 12:15:12 -0600259
Alex Klein231d2da2019-07-22 16:44:45 -0600260 def testSignerTestSuccess(self):
261 """Test successful call handling."""
262 self.PatchObject(image_lib, 'SecurityTest', return_value=True)
263 input_proto = image_pb2.TestImageRequest()
Michael Mortensenc83c9952019-08-05 12:15:12 -0600264 input_proto.image.path = self.image_path
Alex Klein231d2da2019-07-22 16:44:45 -0600265 output_proto = image_pb2.TestImageResult()
Michael Mortensenc83c9952019-08-05 12:15:12 -0600266
Alex Klein231d2da2019-07-22 16:44:45 -0600267 image_controller.SignerTest(input_proto, output_proto, self.api_config)
268
269 def testSignerTestFailure(self):
Michael Mortensenc83c9952019-08-05 12:15:12 -0600270 """Test function output tests."""
271 input_proto = image_pb2.TestImageRequest()
272 input_proto.image.path = self.image_path
Michael Mortensenc83c9952019-08-05 12:15:12 -0600273 output_proto = image_pb2.TestImageResult()
274
Michael Mortensenc83c9952019-08-05 12:15:12 -0600275 self.PatchObject(image_lib, 'SecurityTest', return_value=False)
Alex Klein231d2da2019-07-22 16:44:45 -0600276 image_controller.SignerTest(input_proto, output_proto, self.api_config)
Michael Mortensenc83c9952019-08-05 12:15:12 -0600277 self.assertFalse(output_proto.success)
278
Michael Mortensenc83c9952019-08-05 12:15:12 -0600279
Alex Klein231d2da2019-07-22 16:44:45 -0600280class ImageTestTest(cros_test_lib.MockTempDirTestCase,
281 api_config.ApiConfigMixin):
Alex Klein2557b4f2019-07-11 14:34:00 -0600282 """Image test tests."""
Alex Klein2966e302019-01-17 13:29:38 -0700283
284 def setUp(self):
285 self.image_path = os.path.join(self.tempdir, 'image.bin')
286 self.board = 'board'
287 self.result_directory = os.path.join(self.tempdir, 'results')
288
289 osutils.SafeMakedirs(self.result_directory)
290 osutils.Touch(self.image_path)
291
Alex Klein231d2da2019-07-22 16:44:45 -0600292 def testValidateOnly(self):
293 """Sanity check that a validate only call does not execute any logic."""
294 patch = self.PatchObject(image_service, 'Test')
295
296 input_proto = image_pb2.TestImageRequest()
297 input_proto.image.path = self.image_path
298 input_proto.build_target.name = self.board
299 input_proto.result.directory = self.result_directory
300 output_proto = image_pb2.TestImageResult()
301
302 image_controller.Test(input_proto, output_proto, self.validate_only_config)
303 patch.assert_not_called()
304
Michael Mortensen10146cf2019-11-19 19:59:22 -0700305 def testMockCall(self):
306 """Test that mock call does not execute any logic, returns mocked value."""
307 patch = self.PatchObject(image_service, 'Test')
308
309 input_proto = image_pb2.TestImageRequest()
310 input_proto.image.path = self.image_path
311 input_proto.build_target.name = self.board
312 input_proto.result.directory = self.result_directory
313 output_proto = image_pb2.TestImageResult()
314
315 image_controller.Test(input_proto, output_proto, self.mock_call_config)
316 patch.assert_not_called()
317 self.assertEqual(output_proto.success, True)
318
Michael Mortensen85d38402019-12-12 09:50:29 -0700319 def testMockError(self):
320 """Test that mock call does not execute any logic, returns error."""
321 patch = self.PatchObject(image_service, 'Test')
322
323 input_proto = image_pb2.TestImageRequest()
324 input_proto.image.path = self.image_path
325 input_proto.build_target.name = self.board
326 input_proto.result.directory = self.result_directory
327 output_proto = image_pb2.TestImageResult()
328
329 rc = image_controller.Test(input_proto, output_proto,
330 self.mock_error_config)
331 patch.assert_not_called()
332 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
333
Alex Klein2966e302019-01-17 13:29:38 -0700334 def testTestArgumentValidation(self):
335 """Test function argument validation tests."""
Alex Kleinb7cdbe62019-02-22 11:41:32 -0700336 self.PatchObject(image_service, 'Test', return_value=True)
Alex Klein2966e302019-01-17 13:29:38 -0700337 input_proto = image_pb2.TestImageRequest()
338 output_proto = image_pb2.TestImageResult()
339
340 # Nothing provided.
Alex Klein4f0eb432019-05-02 13:56:04 -0600341 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600342 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700343
344 # Just one argument.
345 input_proto.build_target.name = self.board
Alex Klein4f0eb432019-05-02 13:56:04 -0600346 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600347 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700348
349 # Two arguments provided.
350 input_proto.result.directory = self.result_directory
Alex Klein4f0eb432019-05-02 13:56:04 -0600351 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600352 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700353
354 # Invalid image path.
355 input_proto.image.path = '/invalid/image/path'
Alex Klein4f0eb432019-05-02 13:56:04 -0600356 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600357 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700358
359 # All valid arguments.
360 input_proto.image.path = self.image_path
Alex Klein231d2da2019-07-22 16:44:45 -0600361 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700362
363 def testTestOutputHandling(self):
364 """Test function output tests."""
365 input_proto = image_pb2.TestImageRequest()
366 input_proto.image.path = self.image_path
367 input_proto.build_target.name = self.board
368 input_proto.result.directory = self.result_directory
369 output_proto = image_pb2.TestImageResult()
370
Alex Kleinb7cdbe62019-02-22 11:41:32 -0700371 self.PatchObject(image_service, 'Test', return_value=True)
Alex Klein231d2da2019-07-22 16:44:45 -0600372 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700373 self.assertTrue(output_proto.success)
374
Alex Kleinb7cdbe62019-02-22 11:41:32 -0700375 self.PatchObject(image_service, 'Test', return_value=False)
Alex Klein231d2da2019-07-22 16:44:45 -0600376 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700377 self.assertFalse(output_proto.success)
Jack Neus761e1842020-12-01 18:20:11 +0000378
379
Greg Edelston6902e3d2022-01-27 12:19:38 -0700380class PushImageTest(api_config.ApiConfigMixin):
Jack Neus761e1842020-12-01 18:20:11 +0000381 """Push image test."""
382
Jack Neus761e1842020-12-01 18:20:11 +0000383 def _GetRequest(
384 self,
385 gs_image_dir='gs://chromeos-image-archive/atlas-release/R89-13604.0.0',
386 build_target_name='atlas',
387 profile='foo',
388 sign_types=None,
Jack Neuse77614d2021-10-11 14:10:27 +0000389 dryrun=True,
390 channels=None):
Jack Neus761e1842020-12-01 18:20:11 +0000391 return image_pb2.PushImageRequest(
392 gs_image_dir=gs_image_dir,
393 sysroot=sysroot_pb2.Sysroot(
394 build_target=common_pb2.BuildTarget(name=build_target_name)),
395 profile=common_pb2.Profile(name=profile),
396 sign_types=sign_types,
Jack Neuse77614d2021-10-11 14:10:27 +0000397 dryrun=dryrun,
398 channels=channels)
Jack Neus761e1842020-12-01 18:20:11 +0000399
Greg Edelston6902e3d2022-01-27 12:19:38 -0700400 def _GetResponse(self):
401 return image_pb2.PushImageRequest()
Jack Neus761e1842020-12-01 18:20:11 +0000402
Greg Edelston6902e3d2022-01-27 12:19:38 -0700403 @mock.patch.object(pushimage, 'PushImage', return_value={})
404 def testValidateOnly(self, MockPushImage):
405 """Check that a validate only call does not execute any logic."""
Jack Neus761e1842020-12-01 18:20:11 +0000406 req = self._GetRequest(sign_types=[
407 common_pb2.IMAGE_TYPE_RECOVERY, common_pb2.IMAGE_TYPE_FACTORY,
408 common_pb2.IMAGE_TYPE_FIRMWARE, common_pb2.IMAGE_TYPE_ACCESSORY_USBPD,
409 common_pb2.IMAGE_TYPE_ACCESSORY_RWSIG, common_pb2.IMAGE_TYPE_BASE,
Evan Benn4d061102022-02-14 12:50:45 +1100410 common_pb2.IMAGE_TYPE_GSC_FIRMWARE, common_pb2.IMAGE_TYPE_HPS_FIRMWARE,
Jack Neus761e1842020-12-01 18:20:11 +0000411 ])
Greg Edelston6902e3d2022-01-27 12:19:38 -0700412 rc = image_controller.PushImage(req, self.NewResponse(),
413 self.validate_only_config)
414 MockPushImage.assert_not_called()
415 self.assertEqual(rc, controller.RETURN_CODE_VALID_INPUT)
Jack Neus761e1842020-12-01 18:20:11 +0000416
Greg Edelston6902e3d2022-01-27 12:19:38 -0700417 @mock.patch.object(pushimage, 'PushImage', return_value={})
418 def testValidateOnlyInvalid(self, MockPushImage):
Jack Neus761e1842020-12-01 18:20:11 +0000419 """Check that validate call rejects invalid sign types."""
Jack Neus761e1842020-12-01 18:20:11 +0000420 # Pass unsupported image type.
421 req = self._GetRequest(sign_types=[common_pb2.IMAGE_TYPE_DLC])
Greg Edelston6902e3d2022-01-27 12:19:38 -0700422 rc = image_controller.PushImage(req, self._GetResponse(),
423 self.validate_only_config)
424 MockPushImage.assert_not_called()
425 self.assertEqual(rc, controller.RETURN_CODE_INVALID_INPUT)
Jack Neus761e1842020-12-01 18:20:11 +0000426
Greg Edelston6902e3d2022-01-27 12:19:38 -0700427 @mock.patch.object(pushimage, 'PushImage', return_value={})
428 def testMockCall(self, MockPushImage):
Jack Neus761e1842020-12-01 18:20:11 +0000429 """Test that mock call does not execute any logic, returns mocked value."""
Greg Edelston6902e3d2022-01-27 12:19:38 -0700430 rc = image_controller.PushImage(self._GetRequest(), self._GetResponse(),
Jack Neus761e1842020-12-01 18:20:11 +0000431 self.mock_call_config)
Greg Edelston6902e3d2022-01-27 12:19:38 -0700432 MockPushImage.assert_not_called()
Jack Neus761e1842020-12-01 18:20:11 +0000433 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
434
Greg Edelston6902e3d2022-01-27 12:19:38 -0700435 @mock.patch.object(pushimage, 'PushImage', return_value={})
436 def testMockError(self, MockPushImage):
Jack Neus761e1842020-12-01 18:20:11 +0000437 """Test that mock call does not execute any logic, returns error."""
Greg Edelston6902e3d2022-01-27 12:19:38 -0700438 rc = image_controller.PushImage(self._GetRequest(), self._GetResponse(),
Jack Neus761e1842020-12-01 18:20:11 +0000439 self.mock_error_config)
Greg Edelston6902e3d2022-01-27 12:19:38 -0700440 MockPushImage.assert_not_called()
Jack Neus761e1842020-12-01 18:20:11 +0000441 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
442
Greg Edelston6902e3d2022-01-27 12:19:38 -0700443 @mock.patch.object(pushimage, 'PushImage', return_value={})
444 def testNoBuildTarget(self, _):
Jack Neus761e1842020-12-01 18:20:11 +0000445 """Test no build target given fails."""
446 request = self._GetRequest(build_target_name='')
Jack Neus761e1842020-12-01 18:20:11 +0000447 with self.assertRaises(cros_build_lib.DieSystemExit):
Greg Edelston6902e3d2022-01-27 12:19:38 -0700448 image_controller.PushImage(request, self._GetResponse(), self.api_config)
Jack Neus761e1842020-12-01 18:20:11 +0000449
Greg Edelston6902e3d2022-01-27 12:19:38 -0700450 @mock.patch.object(pushimage, 'PushImage', return_value={})
451 def testNoGsImageDir(self, _):
Jack Neus761e1842020-12-01 18:20:11 +0000452 """Test no image dir given fails."""
453 request = self._GetRequest(gs_image_dir='')
Jack Neus761e1842020-12-01 18:20:11 +0000454 with self.assertRaises(cros_build_lib.DieSystemExit):
Greg Edelston6902e3d2022-01-27 12:19:38 -0700455 image_controller.PushImage(request, self._GetResponse(), self.api_config)
Jack Neus761e1842020-12-01 18:20:11 +0000456
Greg Edelston6902e3d2022-01-27 12:19:38 -0700457 @mock.patch.object(pushimage, 'PushImage', return_value={})
458 def testCallCorrect(self, MockPushImage):
Jack Neus761e1842020-12-01 18:20:11 +0000459 """Check that a call is called with the correct parameters."""
Jack Neus761e1842020-12-01 18:20:11 +0000460 request = self._GetRequest(
Jack Neuse77614d2021-10-11 14:10:27 +0000461 dryrun=False, profile='', sign_types=[common_pb2.IMAGE_TYPE_RECOVERY],
462 channels=[common_pb2.CHANNEL_DEV, common_pb2.CHANNEL_CANARY])
Jack Neus485a9d22020-12-21 03:15:15 +0000463 request.dest_bucket = 'gs://foo'
Greg Edelston6902e3d2022-01-27 12:19:38 -0700464 image_controller.PushImage(request, self._GetResponse(), self.api_config)
465 MockPushImage.assert_called_with(
Jack Neus761e1842020-12-01 18:20:11 +0000466 request.gs_image_dir,
467 request.sysroot.build_target.name,
468 dry_run=request.dryrun,
Jack Neus485a9d22020-12-21 03:15:15 +0000469 sign_types=['recovery'],
Jack Neuse77614d2021-10-11 14:10:27 +0000470 dest_bucket=request.dest_bucket,
471 force_channels=['dev', 'canary'])
Jack Neus761e1842020-12-01 18:20:11 +0000472
Greg Edelston6902e3d2022-01-27 12:19:38 -0700473 @mock.patch.object(pushimage, 'PushImage', return_value={
474 'dev': ['gs://dev/instr1', 'gs://dev/instr2'],
475 'canary': ['gs://canary/instr1']})
476 def testOutput(self, _):
477 """Check that a call populates the response object."""
478 request = self._GetRequest(
479 profile='', sign_types=[common_pb2.IMAGE_TYPE_RECOVERY],
480 channels=[common_pb2.CHANNEL_DEV, common_pb2.CHANNEL_CANARY])
481 request.dest_bucket = 'gs://foo'
482 response = self._GetResponse()
483 image_controller.PushImage(request, response, self.api_config)
484 self.assertEqual(
485 sorted([i.instructions_file_path for i in response.instructions]),
486 sorted(['gs://dev/instr1', 'gs://dev/instr2', 'gs://canary/instr1']))
487
488 def testCallSucceeds(self, _):
Jack Neus761e1842020-12-01 18:20:11 +0000489 """Check that a (dry run) call is made successfully."""
490 request = self._GetRequest(sign_types=[common_pb2.IMAGE_TYPE_RECOVERY])
Greg Edelston6902e3d2022-01-27 12:19:38 -0700491 rc = image_controller.PushImage(
492 request,
493 self._GetResponse(),
494 self.api_config)
495 self.assertEqual(rc, controller.RETURN_CODE_SUCCESS)
Jack Neus761e1842020-12-01 18:20:11 +0000496
497 def testCallFailsWithBadImageDir(self):
498 """Check that a (dry run) call fails when given a bad gs_image_dir."""
499 request = self._GetRequest(gs_image_dir='foo')
Greg Edelston6902e3d2022-01-27 12:19:38 -0700500 rc = image_controller.PushImage(request, self._GetResponse, self.api_config)
501 self.assertEqual(rc, controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY)