blob: d722936b0b95d1c971fc1fdf0e7414432f771253 [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 Klein8cb365a2019-05-15 16:24:53 -060012from chromite.api import controller
Alex Kleinda35fcf2019-03-07 16:01:15 -070013from chromite.api.controller import sysroot as sysroot_controller
14from chromite.api.gen.chromite.api import sysroot_pb2
15from chromite.lib import build_target_util
16from chromite.lib import cros_build_lib
17from chromite.lib import cros_test_lib
18from chromite.lib import osutils
19from chromite.lib import portage_util
20from chromite.lib import sysroot_lib
21from chromite.service import sysroot as sysroot_service
22
23
24class CreateTest(cros_test_lib.MockTestCase):
25 """Create function tests."""
26
27 def _InputProto(self, build_target=None, profile=None, replace=False,
28 current=False):
29 """Helper to build and input proto instance."""
30 proto = sysroot_pb2.SysrootCreateRequest()
31 if build_target:
32 proto.build_target.name = build_target
33 if profile:
34 proto.profile.name = profile
35 if replace:
36 proto.flags.replace = replace
37 if current:
38 proto.flags.chroot_current = current
39
40 return proto
41
42 def _OutputProto(self):
43 """Helper to build output proto instance."""
44 return sysroot_pb2.SysrootCreateResponse()
45
46 def testArgumentValidation(self):
47 """Test the input argument validation."""
48 # Error when no name provided.
49 in_proto = self._InputProto()
50 out_proto = self._OutputProto()
51 with self.assertRaises(cros_build_lib.DieSystemExit):
52 sysroot_controller.Create(in_proto, out_proto)
53
54 # Valid when board passed.
55 result = sysroot_lib.Sysroot('/sysroot/path')
56 patch = self.PatchObject(sysroot_service, 'Create', return_value=result)
57 in_proto = self._InputProto('board')
58 out_proto = self._OutputProto()
59 sysroot_controller.Create(in_proto, out_proto)
60 patch.assert_called_once()
61
62 def testArgumentHandling(self):
63 """Test the arguments get processed and passed correctly."""
64 sysroot_path = '/sysroot/path'
65
66 sysroot = sysroot_lib.Sysroot(sysroot_path)
67 create_patch = self.PatchObject(sysroot_service, 'Create',
68 return_value=sysroot)
69 target_patch = self.PatchObject(build_target_util, 'BuildTarget')
70 rc_patch = self.PatchObject(sysroot_service, 'SetupBoardRunConfig')
71
72 # Default values.
73 board = 'board'
74 profile = None
75 force = False
76 upgrade_chroot = True
77 in_proto = self._InputProto(build_target=board, profile=profile,
78 replace=force, current=not upgrade_chroot)
79 out_proto = self._OutputProto()
80 sysroot_controller.Create(in_proto, out_proto)
81
82 # Default value checks.
83 target_patch.assert_called_with(name=board, profile=profile)
84 rc_patch.assert_called_with(force=force, upgrade_chroot=upgrade_chroot)
85 self.assertEqual(board, out_proto.sysroot.build_target.name)
86 self.assertEqual(sysroot_path, out_proto.sysroot.path)
87
88 # Not default values.
89 create_patch.reset_mock()
90 board = 'board'
91 profile = 'profile'
92 force = True
93 upgrade_chroot = False
94 in_proto = self._InputProto(build_target=board, profile=profile,
95 replace=force, current=not upgrade_chroot)
96 out_proto = self._OutputProto()
97 sysroot_controller.Create(in_proto, out_proto)
98
99 # Not default value checks.
100 target_patch.assert_called_with(name=board, profile=profile)
101 rc_patch.assert_called_with(force=force, upgrade_chroot=upgrade_chroot)
102 self.assertEqual(board, out_proto.sysroot.build_target.name)
103 self.assertEqual(sysroot_path, out_proto.sysroot.path)
104
105
106class InstallToolchainTest(cros_test_lib.MockTempDirTestCase):
107 """Install toolchain function tests."""
108
109 def setUp(self):
110 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600111 # Avoid running the portageq command.
112 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleinda35fcf2019-03-07 16:01:15 -0700113 self.board = 'board'
114 self.sysroot = os.path.join(self.tempdir, 'board')
115 self.invalid_sysroot = os.path.join(self.tempdir, 'invalid', 'sysroot')
116 osutils.SafeMakedirs(self.sysroot)
117
118 def _InputProto(self, build_target=None, sysroot_path=None,
119 compile_source=False):
Alex Kleind4e1e422019-03-18 16:00:41 -0600120 """Helper to build an input proto instance."""
Alex Kleinda35fcf2019-03-07 16:01:15 -0700121 proto = sysroot_pb2.InstallToolchainRequest()
122 if build_target:
123 proto.sysroot.build_target.name = build_target
124 if sysroot_path:
125 proto.sysroot.path = sysroot_path
126 if compile_source:
127 proto.flags.compile_source = compile_source
128
129 return proto
130
131 def _OutputProto(self):
132 """Helper to build output proto instance."""
133 return sysroot_pb2.InstallToolchainResponse()
134
135 def testArgumentValidation(self):
136 """Test the argument validation."""
137 # Test errors on missing inputs.
138 out_proto = self._OutputProto()
139 # Both missing.
140 in_proto = self._InputProto()
141 with self.assertRaises(cros_build_lib.DieSystemExit):
142 sysroot_controller.InstallToolchain(in_proto, out_proto)
143
144 # Sysroot path missing.
145 in_proto = self._InputProto(build_target=self.board)
146 with self.assertRaises(cros_build_lib.DieSystemExit):
147 sysroot_controller.InstallToolchain(in_proto, out_proto)
148
149 # Build target name missing.
150 in_proto = self._InputProto(sysroot_path=self.sysroot)
151 with self.assertRaises(cros_build_lib.DieSystemExit):
152 sysroot_controller.InstallToolchain(in_proto, out_proto)
153
154 # Both provided, but invalid sysroot path.
155 in_proto = self._InputProto(build_target=self.board,
156 sysroot_path=self.invalid_sysroot)
157 with self.assertRaises(cros_build_lib.DieSystemExit):
158 sysroot_controller.InstallToolchain(in_proto, out_proto)
159
160 def testSuccessOutputHandling(self):
161 """Test the output is processed and recorded correctly."""
162 self.PatchObject(sysroot_service, 'InstallToolchain')
163 out_proto = self._OutputProto()
164 in_proto = self._InputProto(build_target=self.board,
165 sysroot_path=self.sysroot)
166
167 rc = sysroot_controller.InstallToolchain(in_proto, out_proto)
168 self.assertFalse(rc)
169 self.assertFalse(out_proto.failed_packages)
170
171
172 def testErrorOutputHandling(self):
173 """Test the error output is processed and recorded correctly."""
174 out_proto = self._OutputProto()
175 in_proto = self._InputProto(build_target=self.board,
176 sysroot_path=self.sysroot)
177
178 err_pkgs = ['cat/pkg', 'cat2/pkg2']
179 err_cpvs = [portage_util.SplitCPV(pkg, strict=False) for pkg in err_pkgs]
180 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
181 err = sysroot_lib.ToolchainInstallError('Error',
182 cros_build_lib.CommandResult(),
183 tc_info=err_cpvs)
184 self.PatchObject(sysroot_service, 'InstallToolchain', side_effect=err)
185
186 rc = sysroot_controller.InstallToolchain(in_proto, out_proto)
Alex Klein8cb365a2019-05-15 16:24:53 -0600187 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700188 self.assertTrue(out_proto.failed_packages)
189 for package in out_proto.failed_packages:
190 cat_pkg = (package.category, package.package_name)
191 self.assertIn(cat_pkg, expected)
Alex Kleind4e1e422019-03-18 16:00:41 -0600192
193
194class InstallPackagesTest(cros_test_lib.MockTempDirTestCase):
195 """InstallPackages tests."""
196
197 def setUp(self):
198 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600199 # Avoid running the portageq command.
200 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleind4e1e422019-03-18 16:00:41 -0600201 self.build_target = 'board'
202 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
203 osutils.SafeMakedirs(self.sysroot)
204
205 def _InputProto(self, build_target=None, sysroot_path=None,
206 build_source=False):
207 """Helper to build an input proto instance."""
208 instance = sysroot_pb2.InstallPackagesRequest()
209
210 if build_target:
211 instance.sysroot.build_target.name = build_target
212 if sysroot_path:
213 instance.sysroot.path = sysroot_path
214 if build_source:
215 instance.flags.build_source = build_source
216
217 return instance
218
219 def _OutputProto(self):
220 """Helper to build an empty output proto instance."""
221 return sysroot_pb2.InstallPackagesResponse()
222
223 def testArgumentValidationAllMissing(self):
224 """Test missing all arguments."""
225 out_proto = self._OutputProto()
226 in_proto = self._InputProto()
227 with self.assertRaises(cros_build_lib.DieSystemExit):
228 sysroot_controller.InstallPackages(in_proto, out_proto)
229
230 def testArgumentValidationNoSysroot(self):
231 """Test missing sysroot path."""
232 out_proto = self._OutputProto()
233 in_proto = self._InputProto(build_target=self.build_target)
234 with self.assertRaises(cros_build_lib.DieSystemExit):
235 sysroot_controller.InstallPackages(in_proto, out_proto)
236
237 def testArgumentValidationNoBuildTarget(self):
238 """Test missing build target name."""
239 out_proto = self._OutputProto()
240 in_proto = self._InputProto(sysroot_path=self.sysroot)
241 with self.assertRaises(cros_build_lib.DieSystemExit):
242 sysroot_controller.InstallPackages(in_proto, out_proto)
243
244 def testArgumentValidationInvalidSysroot(self):
245 """Test sysroot that hasn't had the toolchain installed."""
246 out_proto = self._OutputProto()
247 in_proto = self._InputProto(build_target=self.build_target,
248 sysroot_path=self.sysroot)
249 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
250 return_value=False)
251 with self.assertRaises(cros_build_lib.DieSystemExit):
252 sysroot_controller.InstallPackages(in_proto, out_proto)
253
254 def testSuccessOutputHandling(self):
255 """Test successful call output handling."""
256 # Prevent argument validation error.
257 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
258 return_value=True)
259
260 in_proto = self._InputProto(build_target=self.build_target,
261 sysroot_path=self.sysroot)
262 out_proto = self._OutputProto()
263 self.PatchObject(sysroot_service, 'BuildPackages')
264
265 rc = sysroot_controller.InstallPackages(in_proto, out_proto)
266 self.assertFalse(rc)
267 self.assertFalse(out_proto.failed_packages)
268
269 def testFailureOutputHandling(self):
270 """Test failed package handling."""
271 # Prevent argument validation error.
272 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
273 return_value=True)
274
275 in_proto = self._InputProto(build_target=self.build_target,
276 sysroot_path=self.sysroot)
277 out_proto = self._OutputProto()
278
279 # Failed package info and expected list for verification.
280 err_pkgs = ['cat/pkg', 'cat2/pkg2']
281 err_cpvs = [portage_util.SplitCPV(cpv, strict=False) for cpv in err_pkgs]
282 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
283
284 # Force error to be raised with the packages.
285 error = sysroot_lib.PackageInstallError('Error',
286 cros_build_lib.CommandResult(),
287 packages=err_cpvs)
288 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
289
290 rc = sysroot_controller.InstallPackages(in_proto, out_proto)
Alex Klein2557b4f2019-07-11 14:34:00 -0600291 # This needs to return 2 to indicate the available error response.
292 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleind4e1e422019-03-18 16:00:41 -0600293 for package in out_proto.failed_packages:
294 cat_pkg = (package.category, package.package_name)
295 self.assertIn(cat_pkg, expected)
Alex Klein2557b4f2019-07-11 14:34:00 -0600296
297 def testNoPackageFailureOutputHandling(self):
298 """Test failure handling without packages to report."""
299 # Prevent argument validation error.
300 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
301 return_value=True)
302
303 in_proto = self._InputProto(build_target=self.build_target,
304 sysroot_path=self.sysroot)
305 out_proto = self._OutputProto()
306
307 # Force error to be raised with no packages.
308 error = sysroot_lib.PackageInstallError('Error',
309 cros_build_lib.CommandResult(),
310 packages=[])
311 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
312
313 rc = sysroot_controller.InstallPackages(in_proto, out_proto)
314 # All we really care about is it's not 0 or 2 (response available), so
315 # test for that rather than a specific return code.
316 self.assertTrue(rc)
317 self.assertNotEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE,
318 rc)