blob: 793f19cf5677465b7d45d5e47fc868c8d3502453 [file] [log] [blame]
Alex Klein2966e302019-01-17 13:29:38 -07001# -*- coding: utf-8 -*-
2# Copyright 2019 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
6"""Image service tests."""
7
8from __future__ import print_function
9
10import os
Mike Frysingeref94e4c2020-02-10 23:59:54 -050011import sys
Alex Klein2966e302019-01-17 13:29:38 -070012
Mike Frysinger6db648e2018-07-24 19:57:58 -040013import mock
14
Alex Klein231d2da2019-07-22 16:44:45 -060015from chromite.api import api_config
Alex Klein8cb365a2019-05-15 16:24:53 -060016from chromite.api import controller
17from chromite.api.controller import image as image_controller
Alex Klein7107bdd2019-03-14 17:14:31 -060018from chromite.api.gen.chromite.api import image_pb2
David Burger13e06be2019-05-13 20:33:16 -060019from chromite.api.gen.chromiumos import common_pb2
Alex Klein56355682019-02-07 10:36:54 -070020from chromite.lib import constants
Alex Klein4f0eb432019-05-02 13:56:04 -060021from chromite.lib import cros_build_lib
Alex Klein2966e302019-01-17 13:29:38 -070022from chromite.lib import cros_test_lib
Michael Mortensenc83c9952019-08-05 12:15:12 -060023from chromite.lib import image_lib
Alex Klein2966e302019-01-17 13:29:38 -070024from chromite.lib import osutils
Alex Kleinb7cdbe62019-02-22 11:41:32 -070025from chromite.service import image as image_service
Alex Klein2966e302019-01-17 13:29:38 -070026
27
Mike Frysingeref94e4c2020-02-10 23:59:54 -050028assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
29
30
Alex Klein231d2da2019-07-22 16:44:45 -060031class CreateTest(cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin):
Alex Klein56355682019-02-07 10:36:54 -070032 """Create image tests."""
33
Alex Klein231d2da2019-07-22 16:44:45 -060034 def setUp(self):
35 self.response = image_pb2.CreateImageResult()
36
Alex Klein21b95022019-05-09 14:14:46 -060037 def _GetRequest(self, board=None, types=None, version=None, builder_path=None,
38 disable_rootfs_verification=False):
39 """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,
46 )
47
Alex Klein231d2da2019-07-22 16:44:45 -060048 def testValidateOnly(self):
49 """Sanity check that a validate only call does not execute any logic."""
50 patch = self.PatchObject(image_service, 'Build')
Alex Klein21b95022019-05-09 14:14:46 -060051
Alex Klein231d2da2019-07-22 16:44:45 -060052 request = self._GetRequest(board='board')
53 image_controller.Create(request, self.response, self.validate_only_config)
54 patch.assert_not_called()
55
Michael Mortensen10146cf2019-11-19 19:59:22 -070056 def testMockCall(self):
57 """Test that mock call does not execute any logic, returns mocked value."""
58 patch = self.PatchObject(image_service, 'Build')
59
60 request = self._GetRequest(board='board')
61 image_controller.Create(request, self.response, self.mock_call_config)
62 patch.assert_not_called()
63 self.assertEqual(self.response.success, True)
64
Michael Mortensen85d38402019-12-12 09:50:29 -070065 def testMockError(self):
66 """Test that mock call does not execute any logic, returns error."""
67 patch = self.PatchObject(image_service, 'Build')
68
69 request = self._GetRequest(board='board')
70 rc = image_controller.Create(request, self.response, self.mock_error_config)
71 patch.assert_not_called()
72 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
73
Alex Klein231d2da2019-07-22 16:44:45 -060074 def testNoBoard(self):
75 """Test no board given fails."""
76 request = self._GetRequest()
Alex Klein56355682019-02-07 10:36:54 -070077
78 # No board should cause it to fail.
Alex Klein4f0eb432019-05-02 13:56:04 -060079 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060080 image_controller.Create(request, self.response, self.api_config)
Alex Klein56355682019-02-07 10:36:54 -070081
Alex Klein21b95022019-05-09 14:14:46 -060082 def testNoTypeSpecified(self):
83 """Test the image type default."""
84 request = self._GetRequest(board='board')
Alex Klein21b95022019-05-09 14:14:46 -060085
Alex Klein1bcd9882019-03-19 13:25:24 -060086 # Failed result to avoid the success handling logic.
87 result = image_service.BuildResult(1, [])
88 build_patch = self.PatchObject(image_service, 'Build', return_value=result)
Alex Klein56355682019-02-07 10:36:54 -070089
Alex Klein231d2da2019-07-22 16:44:45 -060090 image_controller.Create(request, self.response, self.api_config)
Alex Klein56355682019-02-07 10:36:54 -070091 build_patch.assert_called_with(images=[constants.IMAGE_TYPE_BASE],
Alex Klein21b95022019-05-09 14:14:46 -060092 board='board', config=mock.ANY)
Alex Klein56355682019-02-07 10:36:54 -070093
Alex Klein21b95022019-05-09 14:14:46 -060094 def testSingleTypeSpecified(self):
95 """Test it's properly using a specified type."""
96 request = self._GetRequest(board='board', types=[common_pb2.DEV])
Alex Klein21b95022019-05-09 14:14:46 -060097
98 # Failed result to avoid the success handling logic.
99 result = image_service.BuildResult(1, [])
100 build_patch = self.PatchObject(image_service, 'Build', return_value=result)
101
Alex Klein231d2da2019-07-22 16:44:45 -0600102 image_controller.Create(request, self.response, self.api_config)
Alex Klein56355682019-02-07 10:36:54 -0700103 build_patch.assert_called_with(images=[constants.IMAGE_TYPE_DEV],
Alex Klein21b95022019-05-09 14:14:46 -0600104 board='board', config=mock.ANY)
Alex Klein56355682019-02-07 10:36:54 -0700105
Alex Klein21b95022019-05-09 14:14:46 -0600106 def testMultipleAndImpliedTypes(self):
107 """Test multiple types and implied type handling."""
108 # The TEST_VM type should force it to build the test image.
109 types = [common_pb2.BASE, common_pb2.TEST_VM]
110 expected_images = [constants.IMAGE_TYPE_BASE, constants.IMAGE_TYPE_TEST]
111
112 request = self._GetRequest(board='board', types=types)
Alex Klein21b95022019-05-09 14:14:46 -0600113
114 # Failed result to avoid the success handling logic.
115 result = image_service.BuildResult(1, [])
116 build_patch = self.PatchObject(image_service, 'Build', return_value=result)
117
Alex Klein231d2da2019-07-22 16:44:45 -0600118 image_controller.Create(request, self.response, self.api_config)
Alex Klein21b95022019-05-09 14:14:46 -0600119 build_patch.assert_called_with(images=expected_images, board='board',
Alex Klein56355682019-02-07 10:36:54 -0700120 config=mock.ANY)
121
Alex Klein1bcd9882019-03-19 13:25:24 -0600122 def testFailedPackageHandling(self):
123 """Test failed packages are populated correctly."""
124 result = image_service.BuildResult(1, ['foo/bar', 'cat/pkg'])
125 expected_packages = [('foo', 'bar'), ('cat', 'pkg')]
126 self.PatchObject(image_service, 'Build', return_value=result)
127
Alex Klein231d2da2019-07-22 16:44:45 -0600128 input_proto = self._GetRequest(board='board')
Alex Klein1bcd9882019-03-19 13:25:24 -0600129
Alex Klein231d2da2019-07-22 16:44:45 -0600130 rc = image_controller.Create(input_proto, self.response, self.api_config)
131
Alex Klein8cb365a2019-05-15 16:24:53 -0600132 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Klein231d2da2019-07-22 16:44:45 -0600133 for package in self.response.failed_packages:
Alex Klein1bcd9882019-03-19 13:25:24 -0600134 self.assertIn((package.category, package.package_name), expected_packages)
135
Alex Klein2557b4f2019-07-11 14:34:00 -0600136 def testNoPackagesFailureHandling(self):
137 """Test failed packages are populated correctly."""
138 result = image_service.BuildResult(1, [])
139 self.PatchObject(image_service, 'Build', return_value=result)
Alex Kleinb7cdbe62019-02-22 11:41:32 -0700140
Alex Klein2557b4f2019-07-11 14:34:00 -0600141 input_proto = image_pb2.CreateImageRequest()
142 input_proto.build_target.name = 'board'
Alex Klein2557b4f2019-07-11 14:34:00 -0600143
Alex Klein231d2da2019-07-22 16:44:45 -0600144 rc = image_controller.Create(input_proto, self.response, self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600145 self.assertTrue(rc)
146 self.assertNotEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE,
147 rc)
Alex Klein231d2da2019-07-22 16:44:45 -0600148 self.assertFalse(self.response.failed_packages)
Alex Klein2557b4f2019-07-11 14:34:00 -0600149
150
Alex Klein231d2da2019-07-22 16:44:45 -0600151class ImageSignerTestTest(cros_test_lib.MockTempDirTestCase,
152 api_config.ApiConfigMixin):
Michael Mortensenc83c9952019-08-05 12:15:12 -0600153 """Image signer test tests."""
154
155 def setUp(self):
156 self.image_path = os.path.join(self.tempdir, 'image.bin')
Michael Mortensenc83c9952019-08-05 12:15:12 -0600157 self.result_directory = os.path.join(self.tempdir, 'results')
158
159 osutils.SafeMakedirs(self.result_directory)
160 osutils.Touch(self.image_path)
161
Alex Klein231d2da2019-07-22 16:44:45 -0600162 def testValidateOnly(self):
163 """Sanity check that validate-only calls don't execute any logic."""
164 patch = self.PatchObject(image_lib, 'SecurityTest', return_value=True)
165 input_proto = image_pb2.TestImageRequest()
166 input_proto.image.path = self.image_path
167 output_proto = image_pb2.TestImageResult()
168
169 image_controller.SignerTest(input_proto, output_proto,
170 self.validate_only_config)
171
172 patch.assert_not_called()
173
Michael Mortensen10146cf2019-11-19 19:59:22 -0700174 def testMockCall(self):
175 """Test that mock call does not execute any logic, returns mocked value."""
176 patch = self.PatchObject(image_lib, 'SecurityTest', return_value=True)
177 input_proto = image_pb2.TestImageRequest()
178 input_proto.image.path = self.image_path
179 output_proto = image_pb2.TestImageResult()
180
181 image_controller.SignerTest(input_proto, output_proto,
182 self.mock_call_config)
183
184 patch.assert_not_called()
185 self.assertEqual(output_proto.success, True)
186
Michael Mortensen85d38402019-12-12 09:50:29 -0700187 def testMockError(self):
188 """Test that mock call does not execute any logic, returns error."""
189 patch = self.PatchObject(image_lib, 'SecurityTest', return_value=True)
190 input_proto = image_pb2.TestImageRequest()
191 input_proto.image.path = self.image_path
192 output_proto = image_pb2.TestImageResult()
193
194 rc = image_controller.SignerTest(input_proto, output_proto,
195 self.mock_error_config)
196
197 patch.assert_not_called()
198 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
199
Alex Klein231d2da2019-07-22 16:44:45 -0600200 def testSignerTestNoImage(self):
201 """Test function argument validation."""
Michael Mortensenc83c9952019-08-05 12:15:12 -0600202 input_proto = image_pb2.TestImageRequest()
203 output_proto = image_pb2.TestImageResult()
204
205 # Nothing provided.
206 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600207 image_controller.SignerTest(input_proto, output_proto, self.api_config)
Michael Mortensenc83c9952019-08-05 12:15:12 -0600208
Alex Klein231d2da2019-07-22 16:44:45 -0600209 def testSignerTestSuccess(self):
210 """Test successful call handling."""
211 self.PatchObject(image_lib, 'SecurityTest', return_value=True)
212 input_proto = image_pb2.TestImageRequest()
Michael Mortensenc83c9952019-08-05 12:15:12 -0600213 input_proto.image.path = self.image_path
Alex Klein231d2da2019-07-22 16:44:45 -0600214 output_proto = image_pb2.TestImageResult()
Michael Mortensenc83c9952019-08-05 12:15:12 -0600215
Alex Klein231d2da2019-07-22 16:44:45 -0600216 image_controller.SignerTest(input_proto, output_proto, self.api_config)
217
218 def testSignerTestFailure(self):
Michael Mortensenc83c9952019-08-05 12:15:12 -0600219 """Test function output tests."""
220 input_proto = image_pb2.TestImageRequest()
221 input_proto.image.path = self.image_path
Michael Mortensenc83c9952019-08-05 12:15:12 -0600222 output_proto = image_pb2.TestImageResult()
223
Michael Mortensenc83c9952019-08-05 12:15:12 -0600224 self.PatchObject(image_lib, 'SecurityTest', return_value=False)
Alex Klein231d2da2019-07-22 16:44:45 -0600225 image_controller.SignerTest(input_proto, output_proto, self.api_config)
Michael Mortensenc83c9952019-08-05 12:15:12 -0600226 self.assertFalse(output_proto.success)
227
Michael Mortensenc83c9952019-08-05 12:15:12 -0600228
Alex Klein231d2da2019-07-22 16:44:45 -0600229class ImageTestTest(cros_test_lib.MockTempDirTestCase,
230 api_config.ApiConfigMixin):
Alex Klein2557b4f2019-07-11 14:34:00 -0600231 """Image test tests."""
Alex Klein2966e302019-01-17 13:29:38 -0700232
233 def setUp(self):
234 self.image_path = os.path.join(self.tempdir, 'image.bin')
235 self.board = 'board'
236 self.result_directory = os.path.join(self.tempdir, 'results')
237
238 osutils.SafeMakedirs(self.result_directory)
239 osutils.Touch(self.image_path)
240
Alex Klein231d2da2019-07-22 16:44:45 -0600241 def testValidateOnly(self):
242 """Sanity check that a validate only call does not execute any logic."""
243 patch = self.PatchObject(image_service, 'Test')
244
245 input_proto = image_pb2.TestImageRequest()
246 input_proto.image.path = self.image_path
247 input_proto.build_target.name = self.board
248 input_proto.result.directory = self.result_directory
249 output_proto = image_pb2.TestImageResult()
250
251 image_controller.Test(input_proto, output_proto, self.validate_only_config)
252 patch.assert_not_called()
253
Michael Mortensen10146cf2019-11-19 19:59:22 -0700254 def testMockCall(self):
255 """Test that mock call does not execute any logic, returns mocked value."""
256 patch = self.PatchObject(image_service, 'Test')
257
258 input_proto = image_pb2.TestImageRequest()
259 input_proto.image.path = self.image_path
260 input_proto.build_target.name = self.board
261 input_proto.result.directory = self.result_directory
262 output_proto = image_pb2.TestImageResult()
263
264 image_controller.Test(input_proto, output_proto, self.mock_call_config)
265 patch.assert_not_called()
266 self.assertEqual(output_proto.success, True)
267
Michael Mortensen85d38402019-12-12 09:50:29 -0700268 def testMockError(self):
269 """Test that mock call does not execute any logic, returns error."""
270 patch = self.PatchObject(image_service, 'Test')
271
272 input_proto = image_pb2.TestImageRequest()
273 input_proto.image.path = self.image_path
274 input_proto.build_target.name = self.board
275 input_proto.result.directory = self.result_directory
276 output_proto = image_pb2.TestImageResult()
277
278 rc = image_controller.Test(input_proto, output_proto,
279 self.mock_error_config)
280 patch.assert_not_called()
281 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
282
Alex Klein2966e302019-01-17 13:29:38 -0700283 def testTestArgumentValidation(self):
284 """Test function argument validation tests."""
Alex Kleinb7cdbe62019-02-22 11:41:32 -0700285 self.PatchObject(image_service, 'Test', return_value=True)
Alex Klein2966e302019-01-17 13:29:38 -0700286 input_proto = image_pb2.TestImageRequest()
287 output_proto = image_pb2.TestImageResult()
288
289 # Nothing provided.
Alex Klein4f0eb432019-05-02 13:56:04 -0600290 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600291 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700292
293 # Just one argument.
294 input_proto.build_target.name = self.board
Alex Klein4f0eb432019-05-02 13:56:04 -0600295 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600296 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700297
298 # Two arguments provided.
299 input_proto.result.directory = self.result_directory
Alex Klein4f0eb432019-05-02 13:56:04 -0600300 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600301 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700302
303 # Invalid image path.
304 input_proto.image.path = '/invalid/image/path'
Alex Klein4f0eb432019-05-02 13:56:04 -0600305 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600306 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700307
308 # All valid arguments.
309 input_proto.image.path = self.image_path
Alex Klein231d2da2019-07-22 16:44:45 -0600310 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700311
312 def testTestOutputHandling(self):
313 """Test function output tests."""
314 input_proto = image_pb2.TestImageRequest()
315 input_proto.image.path = self.image_path
316 input_proto.build_target.name = self.board
317 input_proto.result.directory = self.result_directory
318 output_proto = image_pb2.TestImageResult()
319
Alex Kleinb7cdbe62019-02-22 11:41:32 -0700320 self.PatchObject(image_service, 'Test', return_value=True)
Alex Klein231d2da2019-07-22 16:44:45 -0600321 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700322 self.assertTrue(output_proto.success)
323
Alex Kleinb7cdbe62019-02-22 11:41:32 -0700324 self.PatchObject(image_service, 'Test', return_value=False)
Alex Klein231d2da2019-07-22 16:44:45 -0600325 image_controller.Test(input_proto, output_proto, self.api_config)
Alex Klein2966e302019-01-17 13:29:38 -0700326 self.assertFalse(output_proto.success)