blob: ec6fba94f194c06cd8b00409eb65b51fec6571ba [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
170 def testArgumentValidation(self):
171 """Test the input argument validation."""
172 # Error when no build target provided.
173 in_proto = self._InputProto()
174 out_proto = self._OutputProto()
175 with self.assertRaises(cros_build_lib.DieSystemExit):
176 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
177 self.api_config)
178
179 # Valid when board is specified.
180 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot',
181 return_value='/path/to/sysroot/tar.bz')
182 in_proto = self._InputProto(build_target='board')
183 out_proto = self._OutputProto()
184 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
185 self.api_config)
186 patch.assert_called_once()
187
188
Alex Klein231d2da2019-07-22 16:44:45 -0600189class InstallToolchainTest(cros_test_lib.MockTempDirTestCase,
190 api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -0700191 """Install toolchain function tests."""
192
193 def setUp(self):
194 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600195 # Avoid running the portageq command.
196 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleinda35fcf2019-03-07 16:01:15 -0700197 self.board = 'board'
198 self.sysroot = os.path.join(self.tempdir, 'board')
199 self.invalid_sysroot = os.path.join(self.tempdir, 'invalid', 'sysroot')
200 osutils.SafeMakedirs(self.sysroot)
201
202 def _InputProto(self, build_target=None, sysroot_path=None,
203 compile_source=False):
Alex Kleind4e1e422019-03-18 16:00:41 -0600204 """Helper to build an input proto instance."""
Alex Kleinda35fcf2019-03-07 16:01:15 -0700205 proto = sysroot_pb2.InstallToolchainRequest()
206 if build_target:
207 proto.sysroot.build_target.name = build_target
208 if sysroot_path:
209 proto.sysroot.path = sysroot_path
210 if compile_source:
211 proto.flags.compile_source = compile_source
212
213 return proto
214
215 def _OutputProto(self):
216 """Helper to build output proto instance."""
217 return sysroot_pb2.InstallToolchainResponse()
218
Alex Klein231d2da2019-07-22 16:44:45 -0600219 def testValidateOnly(self):
220 """Sanity check that a validate only call does not execute any logic."""
221 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
222
223 in_proto = self._InputProto(build_target=self.board,
224 sysroot_path=self.sysroot)
225 sysroot_controller.InstallToolchain(in_proto, self._OutputProto(),
226 self.validate_only_config)
227 patch.assert_not_called()
228
Alex Klein076841b2019-08-29 15:19:39 -0600229 def testMockCall(self):
230 """Sanity check that a mock call does not execute any logic."""
231 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
232 request = self._InputProto()
233 response = self._OutputProto()
234
235 rc = sysroot_controller.InstallToolchain(request, response,
236 self.mock_call_config)
237
238 patch.assert_not_called()
239 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
240
241 def testMockError(self):
242 """Sanity check that a mock error 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_error_config)
249
250 patch.assert_not_called()
251 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
252 self.assertTrue(response.failed_packages)
253
Alex Kleinda35fcf2019-03-07 16:01:15 -0700254 def testArgumentValidation(self):
255 """Test the argument validation."""
256 # Test errors on missing inputs.
257 out_proto = self._OutputProto()
258 # Both missing.
259 in_proto = self._InputProto()
260 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600261 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700262
263 # Sysroot path missing.
264 in_proto = self._InputProto(build_target=self.board)
265 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600266 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700267
268 # Build target name missing.
269 in_proto = self._InputProto(sysroot_path=self.sysroot)
270 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600271 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700272
273 # Both provided, but invalid sysroot path.
274 in_proto = self._InputProto(build_target=self.board,
275 sysroot_path=self.invalid_sysroot)
276 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600277 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700278
279 def testSuccessOutputHandling(self):
280 """Test the output is processed and recorded correctly."""
281 self.PatchObject(sysroot_service, 'InstallToolchain')
282 out_proto = self._OutputProto()
283 in_proto = self._InputProto(build_target=self.board,
284 sysroot_path=self.sysroot)
285
Alex Klein231d2da2019-07-22 16:44:45 -0600286 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
287 self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700288 self.assertFalse(rc)
289 self.assertFalse(out_proto.failed_packages)
290
291
292 def testErrorOutputHandling(self):
293 """Test the error output is processed and recorded correctly."""
294 out_proto = self._OutputProto()
295 in_proto = self._InputProto(build_target=self.board,
296 sysroot_path=self.sysroot)
297
298 err_pkgs = ['cat/pkg', 'cat2/pkg2']
299 err_cpvs = [portage_util.SplitCPV(pkg, strict=False) for pkg in err_pkgs]
300 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
301 err = sysroot_lib.ToolchainInstallError('Error',
302 cros_build_lib.CommandResult(),
303 tc_info=err_cpvs)
304 self.PatchObject(sysroot_service, 'InstallToolchain', side_effect=err)
305
Alex Klein231d2da2019-07-22 16:44:45 -0600306 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
307 self.api_config)
Alex Klein8cb365a2019-05-15 16:24:53 -0600308 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700309 self.assertTrue(out_proto.failed_packages)
310 for package in out_proto.failed_packages:
311 cat_pkg = (package.category, package.package_name)
312 self.assertIn(cat_pkg, expected)
Alex Kleind4e1e422019-03-18 16:00:41 -0600313
314
Alex Klein231d2da2019-07-22 16:44:45 -0600315class InstallPackagesTest(cros_test_lib.MockTempDirTestCase,
316 api_config.ApiConfigMixin):
Alex Kleind4e1e422019-03-18 16:00:41 -0600317 """InstallPackages tests."""
318
319 def setUp(self):
320 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600321 # Avoid running the portageq command.
322 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleind4e1e422019-03-18 16:00:41 -0600323 self.build_target = 'board'
324 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
325 osutils.SafeMakedirs(self.sysroot)
326
327 def _InputProto(self, build_target=None, sysroot_path=None,
328 build_source=False):
329 """Helper to build an input proto instance."""
330 instance = sysroot_pb2.InstallPackagesRequest()
331
332 if build_target:
333 instance.sysroot.build_target.name = build_target
334 if sysroot_path:
335 instance.sysroot.path = sysroot_path
336 if build_source:
337 instance.flags.build_source = build_source
338
339 return instance
340
341 def _OutputProto(self):
342 """Helper to build an empty output proto instance."""
343 return sysroot_pb2.InstallPackagesResponse()
344
Alex Klein231d2da2019-07-22 16:44:45 -0600345 def testValidateOnly(self):
346 """Sanity check that a validate only call does not execute any logic."""
347 patch = self.PatchObject(sysroot_service, 'BuildPackages')
348
349 in_proto = self._InputProto(build_target=self.build_target,
350 sysroot_path=self.sysroot)
351 sysroot_controller.InstallPackages(in_proto, self._OutputProto(),
352 self.validate_only_config)
353 patch.assert_not_called()
354
Alex Klein076841b2019-08-29 15:19:39 -0600355 def testMockCall(self):
356 """Sanity check that a mock call does not execute any logic."""
357 patch = self.PatchObject(sysroot_service, 'BuildPackages')
358 request = self._InputProto()
359 response = self._OutputProto()
360
361 rc = sysroot_controller.InstallPackages(request, response,
362 self.mock_call_config)
363
364 patch.assert_not_called()
365 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
366
367 def testMockError(self):
368 """Sanity check that a mock error 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_error_config)
375
376 patch.assert_not_called()
377 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
378 self.assertTrue(response.failed_packages)
379
Alex Kleind4e1e422019-03-18 16:00:41 -0600380 def testArgumentValidationAllMissing(self):
381 """Test missing all arguments."""
382 out_proto = self._OutputProto()
383 in_proto = self._InputProto()
384 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600385 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600386
387 def testArgumentValidationNoSysroot(self):
388 """Test missing sysroot path."""
389 out_proto = self._OutputProto()
390 in_proto = self._InputProto(build_target=self.build_target)
391 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600392 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600393
394 def testArgumentValidationNoBuildTarget(self):
395 """Test missing build target name."""
396 out_proto = self._OutputProto()
397 in_proto = self._InputProto(sysroot_path=self.sysroot)
398 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600399 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600400
401 def testArgumentValidationInvalidSysroot(self):
402 """Test sysroot that hasn't had the toolchain installed."""
403 out_proto = self._OutputProto()
404 in_proto = self._InputProto(build_target=self.build_target,
405 sysroot_path=self.sysroot)
406 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
407 return_value=False)
408 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600409 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600410
411 def testSuccessOutputHandling(self):
412 """Test successful call output handling."""
413 # Prevent argument validation error.
414 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
415 return_value=True)
416
417 in_proto = self._InputProto(build_target=self.build_target,
418 sysroot_path=self.sysroot)
419 out_proto = self._OutputProto()
420 self.PatchObject(sysroot_service, 'BuildPackages')
421
Alex Klein231d2da2019-07-22 16:44:45 -0600422 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
423 self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600424 self.assertFalse(rc)
425 self.assertFalse(out_proto.failed_packages)
426
427 def testFailureOutputHandling(self):
428 """Test failed package handling."""
429 # Prevent argument validation error.
430 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
431 return_value=True)
432
433 in_proto = self._InputProto(build_target=self.build_target,
434 sysroot_path=self.sysroot)
435 out_proto = self._OutputProto()
436
437 # Failed package info and expected list for verification.
438 err_pkgs = ['cat/pkg', 'cat2/pkg2']
439 err_cpvs = [portage_util.SplitCPV(cpv, strict=False) for cpv in err_pkgs]
440 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
441
442 # Force error to be raised with the packages.
443 error = sysroot_lib.PackageInstallError('Error',
444 cros_build_lib.CommandResult(),
445 packages=err_cpvs)
446 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
447
Alex Klein231d2da2019-07-22 16:44:45 -0600448 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
449 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600450 # This needs to return 2 to indicate the available error response.
451 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleind4e1e422019-03-18 16:00:41 -0600452 for package in out_proto.failed_packages:
453 cat_pkg = (package.category, package.package_name)
454 self.assertIn(cat_pkg, expected)
Alex Klein2557b4f2019-07-11 14:34:00 -0600455
456 def testNoPackageFailureOutputHandling(self):
457 """Test failure handling without packages to report."""
458 # Prevent argument validation error.
459 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
460 return_value=True)
461
462 in_proto = self._InputProto(build_target=self.build_target,
463 sysroot_path=self.sysroot)
464 out_proto = self._OutputProto()
465
466 # Force error to be raised with no packages.
467 error = sysroot_lib.PackageInstallError('Error',
468 cros_build_lib.CommandResult(),
469 packages=[])
470 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
471
Alex Klein231d2da2019-07-22 16:44:45 -0600472 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
473 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600474 # All we really care about is it's not 0 or 2 (response available), so
475 # test for that rather than a specific return code.
476 self.assertTrue(rc)
477 self.assertNotEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE,
478 rc)