blob: 7e06c108dd45692760b52cdc5a99c70ecc915737 [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 Kleinda35fcf2019-03-07 16:01:15 -070061 def testArgumentValidation(self):
62 """Test the input argument validation."""
63 # Error when no name provided.
64 in_proto = self._InputProto()
65 out_proto = self._OutputProto()
66 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060067 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -070068
69 # Valid when board passed.
70 result = sysroot_lib.Sysroot('/sysroot/path')
71 patch = self.PatchObject(sysroot_service, 'Create', return_value=result)
72 in_proto = self._InputProto('board')
73 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -060074 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -070075 patch.assert_called_once()
76
77 def testArgumentHandling(self):
78 """Test the arguments get processed and passed correctly."""
79 sysroot_path = '/sysroot/path'
80
81 sysroot = sysroot_lib.Sysroot(sysroot_path)
82 create_patch = self.PatchObject(sysroot_service, 'Create',
83 return_value=sysroot)
84 target_patch = self.PatchObject(build_target_util, 'BuildTarget')
85 rc_patch = self.PatchObject(sysroot_service, 'SetupBoardRunConfig')
86
87 # Default values.
88 board = 'board'
89 profile = None
90 force = False
91 upgrade_chroot = True
92 in_proto = self._InputProto(build_target=board, profile=profile,
93 replace=force, current=not upgrade_chroot)
94 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -060095 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -070096
97 # Default value checks.
98 target_patch.assert_called_with(name=board, profile=profile)
99 rc_patch.assert_called_with(force=force, upgrade_chroot=upgrade_chroot)
100 self.assertEqual(board, out_proto.sysroot.build_target.name)
101 self.assertEqual(sysroot_path, out_proto.sysroot.path)
102
103 # Not default values.
104 create_patch.reset_mock()
105 board = 'board'
106 profile = 'profile'
107 force = True
108 upgrade_chroot = False
109 in_proto = self._InputProto(build_target=board, profile=profile,
110 replace=force, current=not upgrade_chroot)
111 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600112 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700113
114 # Not default value checks.
115 target_patch.assert_called_with(name=board, profile=profile)
116 rc_patch.assert_called_with(force=force, upgrade_chroot=upgrade_chroot)
117 self.assertEqual(board, out_proto.sysroot.build_target.name)
118 self.assertEqual(sysroot_path, out_proto.sysroot.path)
119
120
Alex Klein231d2da2019-07-22 16:44:45 -0600121class InstallToolchainTest(cros_test_lib.MockTempDirTestCase,
122 api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -0700123 """Install toolchain function tests."""
124
125 def setUp(self):
126 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600127 # Avoid running the portageq command.
128 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleinda35fcf2019-03-07 16:01:15 -0700129 self.board = 'board'
130 self.sysroot = os.path.join(self.tempdir, 'board')
131 self.invalid_sysroot = os.path.join(self.tempdir, 'invalid', 'sysroot')
132 osutils.SafeMakedirs(self.sysroot)
133
134 def _InputProto(self, build_target=None, sysroot_path=None,
135 compile_source=False):
Alex Kleind4e1e422019-03-18 16:00:41 -0600136 """Helper to build an input proto instance."""
Alex Kleinda35fcf2019-03-07 16:01:15 -0700137 proto = sysroot_pb2.InstallToolchainRequest()
138 if build_target:
139 proto.sysroot.build_target.name = build_target
140 if sysroot_path:
141 proto.sysroot.path = sysroot_path
142 if compile_source:
143 proto.flags.compile_source = compile_source
144
145 return proto
146
147 def _OutputProto(self):
148 """Helper to build output proto instance."""
149 return sysroot_pb2.InstallToolchainResponse()
150
Alex Klein231d2da2019-07-22 16:44:45 -0600151 def testValidateOnly(self):
152 """Sanity check that a validate only call does not execute any logic."""
153 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
154
155 in_proto = self._InputProto(build_target=self.board,
156 sysroot_path=self.sysroot)
157 sysroot_controller.InstallToolchain(in_proto, self._OutputProto(),
158 self.validate_only_config)
159 patch.assert_not_called()
160
Alex Kleinda35fcf2019-03-07 16:01:15 -0700161 def testArgumentValidation(self):
162 """Test the argument validation."""
163 # Test errors on missing inputs.
164 out_proto = self._OutputProto()
165 # Both missing.
166 in_proto = self._InputProto()
167 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600168 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700169
170 # Sysroot path missing.
171 in_proto = self._InputProto(build_target=self.board)
172 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600173 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700174
175 # Build target name missing.
176 in_proto = self._InputProto(sysroot_path=self.sysroot)
177 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600178 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700179
180 # Both provided, but invalid sysroot path.
181 in_proto = self._InputProto(build_target=self.board,
182 sysroot_path=self.invalid_sysroot)
183 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600184 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700185
186 def testSuccessOutputHandling(self):
187 """Test the output is processed and recorded correctly."""
188 self.PatchObject(sysroot_service, 'InstallToolchain')
189 out_proto = self._OutputProto()
190 in_proto = self._InputProto(build_target=self.board,
191 sysroot_path=self.sysroot)
192
Alex Klein231d2da2019-07-22 16:44:45 -0600193 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
194 self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700195 self.assertFalse(rc)
196 self.assertFalse(out_proto.failed_packages)
197
198
199 def testErrorOutputHandling(self):
200 """Test the error output is processed and recorded correctly."""
201 out_proto = self._OutputProto()
202 in_proto = self._InputProto(build_target=self.board,
203 sysroot_path=self.sysroot)
204
205 err_pkgs = ['cat/pkg', 'cat2/pkg2']
206 err_cpvs = [portage_util.SplitCPV(pkg, strict=False) for pkg in err_pkgs]
207 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
208 err = sysroot_lib.ToolchainInstallError('Error',
209 cros_build_lib.CommandResult(),
210 tc_info=err_cpvs)
211 self.PatchObject(sysroot_service, 'InstallToolchain', side_effect=err)
212
Alex Klein231d2da2019-07-22 16:44:45 -0600213 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
214 self.api_config)
Alex Klein8cb365a2019-05-15 16:24:53 -0600215 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700216 self.assertTrue(out_proto.failed_packages)
217 for package in out_proto.failed_packages:
218 cat_pkg = (package.category, package.package_name)
219 self.assertIn(cat_pkg, expected)
Alex Kleind4e1e422019-03-18 16:00:41 -0600220
221
Alex Klein231d2da2019-07-22 16:44:45 -0600222class InstallPackagesTest(cros_test_lib.MockTempDirTestCase,
223 api_config.ApiConfigMixin):
Alex Kleind4e1e422019-03-18 16:00:41 -0600224 """InstallPackages tests."""
225
226 def setUp(self):
227 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600228 # Avoid running the portageq command.
229 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleind4e1e422019-03-18 16:00:41 -0600230 self.build_target = 'board'
231 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
232 osutils.SafeMakedirs(self.sysroot)
233
234 def _InputProto(self, build_target=None, sysroot_path=None,
235 build_source=False):
236 """Helper to build an input proto instance."""
237 instance = sysroot_pb2.InstallPackagesRequest()
238
239 if build_target:
240 instance.sysroot.build_target.name = build_target
241 if sysroot_path:
242 instance.sysroot.path = sysroot_path
243 if build_source:
244 instance.flags.build_source = build_source
245
246 return instance
247
248 def _OutputProto(self):
249 """Helper to build an empty output proto instance."""
250 return sysroot_pb2.InstallPackagesResponse()
251
Alex Klein231d2da2019-07-22 16:44:45 -0600252 def testValidateOnly(self):
253 """Sanity check that a validate only call does not execute any logic."""
254 patch = self.PatchObject(sysroot_service, 'BuildPackages')
255
256 in_proto = self._InputProto(build_target=self.build_target,
257 sysroot_path=self.sysroot)
258 sysroot_controller.InstallPackages(in_proto, self._OutputProto(),
259 self.validate_only_config)
260 patch.assert_not_called()
261
Alex Kleind4e1e422019-03-18 16:00:41 -0600262 def testArgumentValidationAllMissing(self):
263 """Test missing all arguments."""
264 out_proto = self._OutputProto()
265 in_proto = self._InputProto()
266 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600267 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600268
269 def testArgumentValidationNoSysroot(self):
270 """Test missing sysroot path."""
271 out_proto = self._OutputProto()
272 in_proto = self._InputProto(build_target=self.build_target)
273 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600274 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600275
276 def testArgumentValidationNoBuildTarget(self):
277 """Test missing build target name."""
278 out_proto = self._OutputProto()
279 in_proto = self._InputProto(sysroot_path=self.sysroot)
280 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600281 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600282
283 def testArgumentValidationInvalidSysroot(self):
284 """Test sysroot that hasn't had the toolchain installed."""
285 out_proto = self._OutputProto()
286 in_proto = self._InputProto(build_target=self.build_target,
287 sysroot_path=self.sysroot)
288 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
289 return_value=False)
290 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600291 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600292
293 def testSuccessOutputHandling(self):
294 """Test successful call output handling."""
295 # Prevent argument validation error.
296 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
297 return_value=True)
298
299 in_proto = self._InputProto(build_target=self.build_target,
300 sysroot_path=self.sysroot)
301 out_proto = self._OutputProto()
302 self.PatchObject(sysroot_service, 'BuildPackages')
303
Alex Klein231d2da2019-07-22 16:44:45 -0600304 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
305 self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600306 self.assertFalse(rc)
307 self.assertFalse(out_proto.failed_packages)
308
309 def testFailureOutputHandling(self):
310 """Test failed package handling."""
311 # Prevent argument validation error.
312 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
313 return_value=True)
314
315 in_proto = self._InputProto(build_target=self.build_target,
316 sysroot_path=self.sysroot)
317 out_proto = self._OutputProto()
318
319 # Failed package info and expected list for verification.
320 err_pkgs = ['cat/pkg', 'cat2/pkg2']
321 err_cpvs = [portage_util.SplitCPV(cpv, strict=False) for cpv in err_pkgs]
322 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
323
324 # Force error to be raised with the packages.
325 error = sysroot_lib.PackageInstallError('Error',
326 cros_build_lib.CommandResult(),
327 packages=err_cpvs)
328 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
329
Alex Klein231d2da2019-07-22 16:44:45 -0600330 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
331 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600332 # This needs to return 2 to indicate the available error response.
333 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleind4e1e422019-03-18 16:00:41 -0600334 for package in out_proto.failed_packages:
335 cat_pkg = (package.category, package.package_name)
336 self.assertIn(cat_pkg, expected)
Alex Klein2557b4f2019-07-11 14:34:00 -0600337
338 def testNoPackageFailureOutputHandling(self):
339 """Test failure handling without packages to report."""
340 # Prevent argument validation error.
341 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
342 return_value=True)
343
344 in_proto = self._InputProto(build_target=self.build_target,
345 sysroot_path=self.sysroot)
346 out_proto = self._OutputProto()
347
348 # Force error to be raised with no packages.
349 error = sysroot_lib.PackageInstallError('Error',
350 cros_build_lib.CommandResult(),
351 packages=[])
352 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
353
Alex Klein231d2da2019-07-22 16:44:45 -0600354 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
355 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600356 # All we really care about is it's not 0 or 2 (response available), so
357 # test for that rather than a specific return code.
358 self.assertTrue(rc)
359 self.assertNotEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE,
360 rc)