blob: d5e304e467a655ebfa10adbc9a0f51ae1b636066 [file] [log] [blame]
Alex Kleinda35fcf2019-03-07 16:01:15 -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"""Sysroot controller tests."""
7
8from __future__ import print_function
9
10import os
11
Alex Klein231d2da2019-07-22 16:44:45 -060012from chromite.api import api_config
Alex Klein8cb365a2019-05-15 16:24:53 -060013from chromite.api import controller
Alex Kleinda35fcf2019-03-07 16:01:15 -070014from chromite.api.controller import sysroot as sysroot_controller
15from chromite.api.gen.chromite.api import sysroot_pb2
16from chromite.lib import build_target_util
17from chromite.lib import cros_build_lib
18from chromite.lib import cros_test_lib
19from chromite.lib import osutils
20from chromite.lib import portage_util
21from chromite.lib import sysroot_lib
22from chromite.service import sysroot as sysroot_service
23
24
Alex Klein231d2da2019-07-22 16:44:45 -060025class CreateTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -070026 """Create function tests."""
27
28 def _InputProto(self, build_target=None, profile=None, replace=False,
29 current=False):
30 """Helper to build and input proto instance."""
31 proto = sysroot_pb2.SysrootCreateRequest()
32 if build_target:
33 proto.build_target.name = build_target
34 if profile:
35 proto.profile.name = profile
36 if replace:
37 proto.flags.replace = replace
38 if current:
39 proto.flags.chroot_current = current
40
41 return proto
42
43 def _OutputProto(self):
44 """Helper to build output proto instance."""
45 return sysroot_pb2.SysrootCreateResponse()
46
Alex Klein231d2da2019-07-22 16:44:45 -060047 def testValidateOnly(self):
48 """Sanity check that a validate only call does not execute any logic."""
49 patch = self.PatchObject(sysroot_service, 'Create')
50
51 board = 'board'
52 profile = None
53 force = False
54 upgrade_chroot = True
55 in_proto = self._InputProto(build_target=board, profile=profile,
56 replace=force, current=not upgrade_chroot)
57 sysroot_controller.Create(in_proto, self._OutputProto(),
58 self.validate_only_config)
59 patch.assert_not_called()
60
Alex Klein076841b2019-08-29 15:19:39 -060061 def testMockCall(self):
62 """Sanity check that a mock call does not execute any logic."""
63 patch = self.PatchObject(sysroot_service, 'Create')
64 request = self._InputProto()
65 response = self._OutputProto()
66
67 rc = sysroot_controller.Create(request, response, self.mock_call_config)
68
69 patch.assert_not_called()
70 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
71
72 def testMockError(self):
73 """Sanity check that a mock error does not execute any logic."""
74 patch = self.PatchObject(sysroot_service, 'Create')
75 request = self._InputProto()
76 response = self._OutputProto()
77
78 rc = sysroot_controller.Create(request, response, self.mock_error_config)
79
80 patch.assert_not_called()
81 self.assertEqual(controller.RETURN_CODE_UNRECOVERABLE, rc)
82
Alex Kleinda35fcf2019-03-07 16:01:15 -070083 def testArgumentValidation(self):
84 """Test the input argument validation."""
85 # Error when no name provided.
86 in_proto = self._InputProto()
87 out_proto = self._OutputProto()
88 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060089 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -070090
91 # Valid when board passed.
92 result = sysroot_lib.Sysroot('/sysroot/path')
93 patch = self.PatchObject(sysroot_service, 'Create', return_value=result)
94 in_proto = self._InputProto('board')
95 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -060096 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -070097 patch.assert_called_once()
98
99 def testArgumentHandling(self):
100 """Test the arguments get processed and passed correctly."""
101 sysroot_path = '/sysroot/path'
102
103 sysroot = sysroot_lib.Sysroot(sysroot_path)
104 create_patch = self.PatchObject(sysroot_service, 'Create',
105 return_value=sysroot)
106 target_patch = self.PatchObject(build_target_util, 'BuildTarget')
107 rc_patch = self.PatchObject(sysroot_service, 'SetupBoardRunConfig')
108
109 # Default values.
110 board = 'board'
111 profile = None
112 force = False
113 upgrade_chroot = True
114 in_proto = self._InputProto(build_target=board, profile=profile,
115 replace=force, current=not upgrade_chroot)
116 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600117 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700118
119 # Default value checks.
120 target_patch.assert_called_with(name=board, profile=profile)
121 rc_patch.assert_called_with(force=force, upgrade_chroot=upgrade_chroot)
122 self.assertEqual(board, out_proto.sysroot.build_target.name)
123 self.assertEqual(sysroot_path, out_proto.sysroot.path)
124
125 # Not default values.
126 create_patch.reset_mock()
127 board = 'board'
128 profile = 'profile'
129 force = True
130 upgrade_chroot = False
131 in_proto = self._InputProto(build_target=board, profile=profile,
132 replace=force, current=not upgrade_chroot)
133 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600134 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700135
136 # Not default value checks.
137 target_patch.assert_called_with(name=board, profile=profile)
138 rc_patch.assert_called_with(force=force, upgrade_chroot=upgrade_chroot)
139 self.assertEqual(board, out_proto.sysroot.build_target.name)
140 self.assertEqual(sysroot_path, out_proto.sysroot.path)
141
142
Michael Mortensen98592f62019-09-27 13:34:18 -0600143class CreateSimpleChromeSysrootTest(cros_test_lib.MockTempDirTestCase,
144 api_config.ApiConfigMixin):
145 """CreateSimpleChromeSysroot function tests."""
146
147 def _InputProto(self, build_target=None, use_flags=None):
148 """Helper to build and input proto instance."""
149 proto = sysroot_pb2.CreateSimpleChromeSysrootRequest()
150 if build_target:
151 proto.build_target.name = build_target
152 if use_flags:
153 proto.use_flags = use_flags
154 return proto
155
156 def _OutputProto(self):
157 """Helper to build output proto instance."""
158 return sysroot_pb2.CreateSimpleChromeSysrootResponse()
159
160 def testValidateOnly(self):
161 """Sanity check that a validate only call does not execute any logic."""
162 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot')
163
164 board = 'board'
165 in_proto = self._InputProto(build_target=board, use_flags=[])
166 sysroot_controller.CreateSimpleChromeSysroot(in_proto, self._OutputProto(),
167 self.validate_only_config)
168 patch.assert_not_called()
169
Michael Mortensen3232ab32020-01-05 19:14:36 -0700170 def testMockCall(self):
171 """Sanity check that a mock call does not execute any logic."""
172 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot')
173
174 board = 'board'
175 in_proto = self._InputProto(build_target=board, use_flags=[])
176 rc = sysroot_controller.CreateSimpleChromeSysroot(in_proto,
177 self._OutputProto(),
178 self.mock_call_config)
179 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
180 patch.assert_not_called()
181
Michael Mortensen98592f62019-09-27 13:34:18 -0600182 def testArgumentValidation(self):
183 """Test the input argument validation."""
184 # Error when no build target provided.
185 in_proto = self._InputProto()
186 out_proto = self._OutputProto()
187 with self.assertRaises(cros_build_lib.DieSystemExit):
188 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
189 self.api_config)
190
191 # Valid when board is specified.
192 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot',
193 return_value='/path/to/sysroot/tar.bz')
194 in_proto = self._InputProto(build_target='board')
195 out_proto = self._OutputProto()
196 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
197 self.api_config)
198 patch.assert_called_once()
199
200
Alex Klein231d2da2019-07-22 16:44:45 -0600201class InstallToolchainTest(cros_test_lib.MockTempDirTestCase,
202 api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -0700203 """Install toolchain function tests."""
204
205 def setUp(self):
206 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600207 # Avoid running the portageq command.
208 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleinda35fcf2019-03-07 16:01:15 -0700209 self.board = 'board'
210 self.sysroot = os.path.join(self.tempdir, 'board')
211 self.invalid_sysroot = os.path.join(self.tempdir, 'invalid', 'sysroot')
212 osutils.SafeMakedirs(self.sysroot)
213
214 def _InputProto(self, build_target=None, sysroot_path=None,
215 compile_source=False):
Alex Kleind4e1e422019-03-18 16:00:41 -0600216 """Helper to build an input proto instance."""
Alex Kleinda35fcf2019-03-07 16:01:15 -0700217 proto = sysroot_pb2.InstallToolchainRequest()
218 if build_target:
219 proto.sysroot.build_target.name = build_target
220 if sysroot_path:
221 proto.sysroot.path = sysroot_path
222 if compile_source:
223 proto.flags.compile_source = compile_source
224
225 return proto
226
227 def _OutputProto(self):
228 """Helper to build output proto instance."""
229 return sysroot_pb2.InstallToolchainResponse()
230
Alex Klein231d2da2019-07-22 16:44:45 -0600231 def testValidateOnly(self):
232 """Sanity check that a validate only call does not execute any logic."""
233 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
234
235 in_proto = self._InputProto(build_target=self.board,
236 sysroot_path=self.sysroot)
237 sysroot_controller.InstallToolchain(in_proto, self._OutputProto(),
238 self.validate_only_config)
239 patch.assert_not_called()
240
Alex Klein076841b2019-08-29 15:19:39 -0600241 def testMockCall(self):
242 """Sanity check that a mock call does not execute any logic."""
243 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
244 request = self._InputProto()
245 response = self._OutputProto()
246
247 rc = sysroot_controller.InstallToolchain(request, response,
248 self.mock_call_config)
249
250 patch.assert_not_called()
251 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
252
253 def testMockError(self):
254 """Sanity check that a mock error does not execute any logic."""
255 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
256 request = self._InputProto()
257 response = self._OutputProto()
258
259 rc = sysroot_controller.InstallToolchain(request, response,
260 self.mock_error_config)
261
262 patch.assert_not_called()
263 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
264 self.assertTrue(response.failed_packages)
265
Alex Kleinda35fcf2019-03-07 16:01:15 -0700266 def testArgumentValidation(self):
267 """Test the argument validation."""
268 # Test errors on missing inputs.
269 out_proto = self._OutputProto()
270 # Both missing.
271 in_proto = self._InputProto()
272 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600273 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700274
275 # Sysroot path missing.
276 in_proto = self._InputProto(build_target=self.board)
277 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600278 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700279
280 # Build target name missing.
281 in_proto = self._InputProto(sysroot_path=self.sysroot)
282 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600283 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700284
285 # Both provided, but invalid sysroot path.
286 in_proto = self._InputProto(build_target=self.board,
287 sysroot_path=self.invalid_sysroot)
288 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600289 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700290
291 def testSuccessOutputHandling(self):
292 """Test the output is processed and recorded correctly."""
293 self.PatchObject(sysroot_service, 'InstallToolchain')
294 out_proto = self._OutputProto()
295 in_proto = self._InputProto(build_target=self.board,
296 sysroot_path=self.sysroot)
297
Alex Klein231d2da2019-07-22 16:44:45 -0600298 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
299 self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700300 self.assertFalse(rc)
301 self.assertFalse(out_proto.failed_packages)
302
303
304 def testErrorOutputHandling(self):
305 """Test the error output is processed and recorded correctly."""
306 out_proto = self._OutputProto()
307 in_proto = self._InputProto(build_target=self.board,
308 sysroot_path=self.sysroot)
309
310 err_pkgs = ['cat/pkg', 'cat2/pkg2']
311 err_cpvs = [portage_util.SplitCPV(pkg, strict=False) for pkg in err_pkgs]
312 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
313 err = sysroot_lib.ToolchainInstallError('Error',
314 cros_build_lib.CommandResult(),
315 tc_info=err_cpvs)
316 self.PatchObject(sysroot_service, 'InstallToolchain', side_effect=err)
317
Alex Klein231d2da2019-07-22 16:44:45 -0600318 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
319 self.api_config)
Alex Klein8cb365a2019-05-15 16:24:53 -0600320 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700321 self.assertTrue(out_proto.failed_packages)
322 for package in out_proto.failed_packages:
323 cat_pkg = (package.category, package.package_name)
324 self.assertIn(cat_pkg, expected)
Alex Kleind4e1e422019-03-18 16:00:41 -0600325
326
Alex Klein231d2da2019-07-22 16:44:45 -0600327class InstallPackagesTest(cros_test_lib.MockTempDirTestCase,
328 api_config.ApiConfigMixin):
Alex Kleind4e1e422019-03-18 16:00:41 -0600329 """InstallPackages tests."""
330
331 def setUp(self):
332 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600333 # Avoid running the portageq command.
334 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleind4e1e422019-03-18 16:00:41 -0600335 self.build_target = 'board'
336 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
337 osutils.SafeMakedirs(self.sysroot)
338
339 def _InputProto(self, build_target=None, sysroot_path=None,
340 build_source=False):
341 """Helper to build an input proto instance."""
342 instance = sysroot_pb2.InstallPackagesRequest()
343
344 if build_target:
345 instance.sysroot.build_target.name = build_target
346 if sysroot_path:
347 instance.sysroot.path = sysroot_path
348 if build_source:
349 instance.flags.build_source = build_source
350
351 return instance
352
353 def _OutputProto(self):
354 """Helper to build an empty output proto instance."""
355 return sysroot_pb2.InstallPackagesResponse()
356
Alex Klein231d2da2019-07-22 16:44:45 -0600357 def testValidateOnly(self):
358 """Sanity check that a validate only call does not execute any logic."""
359 patch = self.PatchObject(sysroot_service, 'BuildPackages')
360
361 in_proto = self._InputProto(build_target=self.build_target,
362 sysroot_path=self.sysroot)
363 sysroot_controller.InstallPackages(in_proto, self._OutputProto(),
364 self.validate_only_config)
365 patch.assert_not_called()
366
Alex Klein076841b2019-08-29 15:19:39 -0600367 def testMockCall(self):
368 """Sanity check that a mock call does not execute any logic."""
369 patch = self.PatchObject(sysroot_service, 'BuildPackages')
370 request = self._InputProto()
371 response = self._OutputProto()
372
373 rc = sysroot_controller.InstallPackages(request, response,
374 self.mock_call_config)
375
376 patch.assert_not_called()
377 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
378
379 def testMockError(self):
380 """Sanity check that a mock error does not execute any logic."""
381 patch = self.PatchObject(sysroot_service, 'BuildPackages')
382 request = self._InputProto()
383 response = self._OutputProto()
384
385 rc = sysroot_controller.InstallPackages(request, response,
386 self.mock_error_config)
387
388 patch.assert_not_called()
389 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
390 self.assertTrue(response.failed_packages)
391
Alex Kleind4e1e422019-03-18 16:00:41 -0600392 def testArgumentValidationAllMissing(self):
393 """Test missing all arguments."""
394 out_proto = self._OutputProto()
395 in_proto = self._InputProto()
396 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600397 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600398
399 def testArgumentValidationNoSysroot(self):
400 """Test missing sysroot path."""
401 out_proto = self._OutputProto()
402 in_proto = self._InputProto(build_target=self.build_target)
403 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600404 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600405
406 def testArgumentValidationNoBuildTarget(self):
407 """Test missing build target name."""
408 out_proto = self._OutputProto()
409 in_proto = self._InputProto(sysroot_path=self.sysroot)
410 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600411 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600412
413 def testArgumentValidationInvalidSysroot(self):
414 """Test sysroot that hasn't had the toolchain installed."""
415 out_proto = self._OutputProto()
416 in_proto = self._InputProto(build_target=self.build_target,
417 sysroot_path=self.sysroot)
418 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
419 return_value=False)
420 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600421 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600422
423 def testSuccessOutputHandling(self):
424 """Test successful call output handling."""
425 # Prevent argument validation error.
426 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
427 return_value=True)
428
429 in_proto = self._InputProto(build_target=self.build_target,
430 sysroot_path=self.sysroot)
431 out_proto = self._OutputProto()
432 self.PatchObject(sysroot_service, 'BuildPackages')
433
Alex Klein231d2da2019-07-22 16:44:45 -0600434 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
435 self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600436 self.assertFalse(rc)
437 self.assertFalse(out_proto.failed_packages)
438
439 def testFailureOutputHandling(self):
440 """Test failed package handling."""
441 # Prevent argument validation error.
442 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
443 return_value=True)
444
445 in_proto = self._InputProto(build_target=self.build_target,
446 sysroot_path=self.sysroot)
447 out_proto = self._OutputProto()
448
449 # Failed package info and expected list for verification.
450 err_pkgs = ['cat/pkg', 'cat2/pkg2']
451 err_cpvs = [portage_util.SplitCPV(cpv, strict=False) for cpv in err_pkgs]
452 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
453
454 # Force error to be raised with the packages.
455 error = sysroot_lib.PackageInstallError('Error',
456 cros_build_lib.CommandResult(),
457 packages=err_cpvs)
458 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
459
Alex Klein231d2da2019-07-22 16:44:45 -0600460 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
461 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600462 # This needs to return 2 to indicate the available error response.
463 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleind4e1e422019-03-18 16:00:41 -0600464 for package in out_proto.failed_packages:
465 cat_pkg = (package.category, package.package_name)
466 self.assertIn(cat_pkg, expected)
Alex Klein2557b4f2019-07-11 14:34:00 -0600467
468 def testNoPackageFailureOutputHandling(self):
469 """Test failure handling without packages to report."""
470 # Prevent argument validation error.
471 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
472 return_value=True)
473
474 in_proto = self._InputProto(build_target=self.build_target,
475 sysroot_path=self.sysroot)
476 out_proto = self._OutputProto()
477
478 # Force error to be raised with no packages.
479 error = sysroot_lib.PackageInstallError('Error',
480 cros_build_lib.CommandResult(),
481 packages=[])
482 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
483
Alex Klein231d2da2019-07-22 16:44:45 -0600484 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
485 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600486 # All we really care about is it's not 0 or 2 (response available), so
487 # test for that rather than a specific return code.
488 self.assertTrue(rc)
489 self.assertNotEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE,
490 rc)