blob: 75790e9f256723ced3fd26bd1f56b8e1bb0d1ec6 [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
Alex Klein231d2da2019-07-22 16:44:45 -0600143class InstallToolchainTest(cros_test_lib.MockTempDirTestCase,
144 api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -0700145 """Install toolchain function tests."""
146
147 def setUp(self):
148 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600149 # Avoid running the portageq command.
150 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleinda35fcf2019-03-07 16:01:15 -0700151 self.board = 'board'
152 self.sysroot = os.path.join(self.tempdir, 'board')
153 self.invalid_sysroot = os.path.join(self.tempdir, 'invalid', 'sysroot')
154 osutils.SafeMakedirs(self.sysroot)
155
156 def _InputProto(self, build_target=None, sysroot_path=None,
157 compile_source=False):
Alex Kleind4e1e422019-03-18 16:00:41 -0600158 """Helper to build an input proto instance."""
Alex Kleinda35fcf2019-03-07 16:01:15 -0700159 proto = sysroot_pb2.InstallToolchainRequest()
160 if build_target:
161 proto.sysroot.build_target.name = build_target
162 if sysroot_path:
163 proto.sysroot.path = sysroot_path
164 if compile_source:
165 proto.flags.compile_source = compile_source
166
167 return proto
168
169 def _OutputProto(self):
170 """Helper to build output proto instance."""
171 return sysroot_pb2.InstallToolchainResponse()
172
Alex Klein231d2da2019-07-22 16:44:45 -0600173 def testValidateOnly(self):
174 """Sanity check that a validate only call does not execute any logic."""
175 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
176
177 in_proto = self._InputProto(build_target=self.board,
178 sysroot_path=self.sysroot)
179 sysroot_controller.InstallToolchain(in_proto, self._OutputProto(),
180 self.validate_only_config)
181 patch.assert_not_called()
182
Alex Klein076841b2019-08-29 15:19:39 -0600183 def testMockCall(self):
184 """Sanity check that a mock call does not execute any logic."""
185 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
186 request = self._InputProto()
187 response = self._OutputProto()
188
189 rc = sysroot_controller.InstallToolchain(request, response,
190 self.mock_call_config)
191
192 patch.assert_not_called()
193 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
194
195 def testMockError(self):
196 """Sanity check that a mock error does not execute any logic."""
197 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
198 request = self._InputProto()
199 response = self._OutputProto()
200
201 rc = sysroot_controller.InstallToolchain(request, response,
202 self.mock_error_config)
203
204 patch.assert_not_called()
205 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
206 self.assertTrue(response.failed_packages)
207
Alex Kleinda35fcf2019-03-07 16:01:15 -0700208 def testArgumentValidation(self):
209 """Test the argument validation."""
210 # Test errors on missing inputs.
211 out_proto = self._OutputProto()
212 # Both missing.
213 in_proto = self._InputProto()
214 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600215 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700216
217 # Sysroot path missing.
218 in_proto = self._InputProto(build_target=self.board)
219 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600220 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700221
222 # Build target name missing.
223 in_proto = self._InputProto(sysroot_path=self.sysroot)
224 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600225 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700226
227 # Both provided, but invalid sysroot path.
228 in_proto = self._InputProto(build_target=self.board,
229 sysroot_path=self.invalid_sysroot)
230 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600231 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700232
233 def testSuccessOutputHandling(self):
234 """Test the output is processed and recorded correctly."""
235 self.PatchObject(sysroot_service, 'InstallToolchain')
236 out_proto = self._OutputProto()
237 in_proto = self._InputProto(build_target=self.board,
238 sysroot_path=self.sysroot)
239
Alex Klein231d2da2019-07-22 16:44:45 -0600240 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
241 self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700242 self.assertFalse(rc)
243 self.assertFalse(out_proto.failed_packages)
244
245
246 def testErrorOutputHandling(self):
247 """Test the error output is processed and recorded correctly."""
248 out_proto = self._OutputProto()
249 in_proto = self._InputProto(build_target=self.board,
250 sysroot_path=self.sysroot)
251
252 err_pkgs = ['cat/pkg', 'cat2/pkg2']
253 err_cpvs = [portage_util.SplitCPV(pkg, strict=False) for pkg in err_pkgs]
254 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
255 err = sysroot_lib.ToolchainInstallError('Error',
256 cros_build_lib.CommandResult(),
257 tc_info=err_cpvs)
258 self.PatchObject(sysroot_service, 'InstallToolchain', side_effect=err)
259
Alex Klein231d2da2019-07-22 16:44:45 -0600260 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
261 self.api_config)
Alex Klein8cb365a2019-05-15 16:24:53 -0600262 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700263 self.assertTrue(out_proto.failed_packages)
264 for package in out_proto.failed_packages:
265 cat_pkg = (package.category, package.package_name)
266 self.assertIn(cat_pkg, expected)
Alex Kleind4e1e422019-03-18 16:00:41 -0600267
268
Alex Klein231d2da2019-07-22 16:44:45 -0600269class InstallPackagesTest(cros_test_lib.MockTempDirTestCase,
270 api_config.ApiConfigMixin):
Alex Kleind4e1e422019-03-18 16:00:41 -0600271 """InstallPackages tests."""
272
273 def setUp(self):
274 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600275 # Avoid running the portageq command.
276 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleind4e1e422019-03-18 16:00:41 -0600277 self.build_target = 'board'
278 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
279 osutils.SafeMakedirs(self.sysroot)
280
281 def _InputProto(self, build_target=None, sysroot_path=None,
282 build_source=False):
283 """Helper to build an input proto instance."""
284 instance = sysroot_pb2.InstallPackagesRequest()
285
286 if build_target:
287 instance.sysroot.build_target.name = build_target
288 if sysroot_path:
289 instance.sysroot.path = sysroot_path
290 if build_source:
291 instance.flags.build_source = build_source
292
293 return instance
294
295 def _OutputProto(self):
296 """Helper to build an empty output proto instance."""
297 return sysroot_pb2.InstallPackagesResponse()
298
Alex Klein231d2da2019-07-22 16:44:45 -0600299 def testValidateOnly(self):
300 """Sanity check that a validate only call does not execute any logic."""
301 patch = self.PatchObject(sysroot_service, 'BuildPackages')
302
303 in_proto = self._InputProto(build_target=self.build_target,
304 sysroot_path=self.sysroot)
305 sysroot_controller.InstallPackages(in_proto, self._OutputProto(),
306 self.validate_only_config)
307 patch.assert_not_called()
308
Alex Klein076841b2019-08-29 15:19:39 -0600309 def testMockCall(self):
310 """Sanity check that a mock call does not execute any logic."""
311 patch = self.PatchObject(sysroot_service, 'BuildPackages')
312 request = self._InputProto()
313 response = self._OutputProto()
314
315 rc = sysroot_controller.InstallPackages(request, response,
316 self.mock_call_config)
317
318 patch.assert_not_called()
319 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
320
321 def testMockError(self):
322 """Sanity check that a mock error does not execute any logic."""
323 patch = self.PatchObject(sysroot_service, 'BuildPackages')
324 request = self._InputProto()
325 response = self._OutputProto()
326
327 rc = sysroot_controller.InstallPackages(request, response,
328 self.mock_error_config)
329
330 patch.assert_not_called()
331 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
332 self.assertTrue(response.failed_packages)
333
Alex Kleind4e1e422019-03-18 16:00:41 -0600334 def testArgumentValidationAllMissing(self):
335 """Test missing all arguments."""
336 out_proto = self._OutputProto()
337 in_proto = self._InputProto()
338 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600339 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600340
341 def testArgumentValidationNoSysroot(self):
342 """Test missing sysroot path."""
343 out_proto = self._OutputProto()
344 in_proto = self._InputProto(build_target=self.build_target)
345 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600346 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600347
348 def testArgumentValidationNoBuildTarget(self):
349 """Test missing build target name."""
350 out_proto = self._OutputProto()
351 in_proto = self._InputProto(sysroot_path=self.sysroot)
352 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600353 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600354
355 def testArgumentValidationInvalidSysroot(self):
356 """Test sysroot that hasn't had the toolchain installed."""
357 out_proto = self._OutputProto()
358 in_proto = self._InputProto(build_target=self.build_target,
359 sysroot_path=self.sysroot)
360 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
361 return_value=False)
362 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600363 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600364
365 def testSuccessOutputHandling(self):
366 """Test successful call output handling."""
367 # Prevent argument validation error.
368 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
369 return_value=True)
370
371 in_proto = self._InputProto(build_target=self.build_target,
372 sysroot_path=self.sysroot)
373 out_proto = self._OutputProto()
374 self.PatchObject(sysroot_service, 'BuildPackages')
375
Alex Klein231d2da2019-07-22 16:44:45 -0600376 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
377 self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600378 self.assertFalse(rc)
379 self.assertFalse(out_proto.failed_packages)
380
381 def testFailureOutputHandling(self):
382 """Test failed package handling."""
383 # Prevent argument validation error.
384 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
385 return_value=True)
386
387 in_proto = self._InputProto(build_target=self.build_target,
388 sysroot_path=self.sysroot)
389 out_proto = self._OutputProto()
390
391 # Failed package info and expected list for verification.
392 err_pkgs = ['cat/pkg', 'cat2/pkg2']
393 err_cpvs = [portage_util.SplitCPV(cpv, strict=False) for cpv in err_pkgs]
394 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
395
396 # Force error to be raised with the packages.
397 error = sysroot_lib.PackageInstallError('Error',
398 cros_build_lib.CommandResult(),
399 packages=err_cpvs)
400 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
401
Alex Klein231d2da2019-07-22 16:44:45 -0600402 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
403 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600404 # This needs to return 2 to indicate the available error response.
405 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleind4e1e422019-03-18 16:00:41 -0600406 for package in out_proto.failed_packages:
407 cat_pkg = (package.category, package.package_name)
408 self.assertIn(cat_pkg, expected)
Alex Klein2557b4f2019-07-11 14:34:00 -0600409
410 def testNoPackageFailureOutputHandling(self):
411 """Test failure handling without packages to report."""
412 # Prevent argument validation error.
413 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
414 return_value=True)
415
416 in_proto = self._InputProto(build_target=self.build_target,
417 sysroot_path=self.sysroot)
418 out_proto = self._OutputProto()
419
420 # Force error to be raised with no packages.
421 error = sysroot_lib.PackageInstallError('Error',
422 cros_build_lib.CommandResult(),
423 packages=[])
424 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
425
Alex Klein231d2da2019-07-22 16:44:45 -0600426 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
427 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600428 # All we really care about is it's not 0 or 2 (response available), so
429 # test for that rather than a specific return code.
430 self.assertTrue(rc)
431 self.assertNotEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE,
432 rc)