blob: d41372b75c27ce8f85e9297583008eccf29df724 [file] [log] [blame]
Alex Kleinda35fcf2019-03-07 16:01:15 -07001# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Sysroot controller tests."""
6
Michael Mortensen798ee192020-01-17 13:04:43 -07007import datetime
Alex Kleinda35fcf2019-03-07 16:01:15 -07008import os
Lizzy Preslandfc1db002022-05-06 18:19:49 +00009from typing import Union
Alex Kleinda35fcf2019-03-07 16:01:15 -070010
Alex Klein231d2da2019-07-22 16:44:45 -060011from chromite.api import api_config
Alex Klein8cb365a2019-05-15 16:24:53 -060012from chromite.api import controller
Alex Kleinca572ee2020-09-03 10:47:14 -060013from chromite.api.controller import controller_util
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
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -070016from chromite.api.gen.chromiumos import common_pb2
LaMont Jonesc0343fa2020-08-12 18:58:31 -060017from chromite.lib import binpkg
Alex Kleinda35fcf2019-03-07 16:01:15 -070018from chromite.lib import cros_build_lib
19from chromite.lib import cros_test_lib
20from chromite.lib import osutils
Alex Kleinda35fcf2019-03-07 16:01:15 -070021from chromite.lib import sysroot_lib
Alex Klein18a60af2020-06-11 12:08:47 -060022from chromite.lib.parser import package_info
Alex Kleinda35fcf2019-03-07 16:01:15 -070023from chromite.service import sysroot as sysroot_service
24
25
Alex Klein231d2da2019-07-22 16:44:45 -060026class CreateTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -070027 """Create function tests."""
28
Alex Kleind066b0f2022-07-28 08:47:35 -060029 def _InputProto(self,
30 build_target=None,
31 profile=None,
32 replace=False,
33 current=False,
34 package_indexes=None):
Alex Kleinda35fcf2019-03-07 16:01:15 -070035 """Helper to build and input proto instance."""
36 proto = sysroot_pb2.SysrootCreateRequest()
37 if build_target:
38 proto.build_target.name = build_target
39 if profile:
40 proto.profile.name = profile
41 if replace:
42 proto.flags.replace = replace
43 if current:
44 proto.flags.chroot_current = current
LaMont Jonesc0343fa2020-08-12 18:58:31 -060045 if package_indexes:
46 proto.package_indexes.extend(package_indexes)
Alex Kleinda35fcf2019-03-07 16:01:15 -070047
48 return proto
49
50 def _OutputProto(self):
51 """Helper to build output proto instance."""
52 return sysroot_pb2.SysrootCreateResponse()
53
Alex Klein231d2da2019-07-22 16:44:45 -060054 def testValidateOnly(self):
55 """Sanity check that a validate only call does not execute any logic."""
56 patch = self.PatchObject(sysroot_service, 'Create')
57
58 board = 'board'
59 profile = None
60 force = False
61 upgrade_chroot = True
Alex Kleind066b0f2022-07-28 08:47:35 -060062 in_proto = self._InputProto(
63 build_target=board,
64 profile=profile,
65 replace=force,
66 current=not upgrade_chroot)
Alex Klein231d2da2019-07-22 16:44:45 -060067 sysroot_controller.Create(in_proto, self._OutputProto(),
68 self.validate_only_config)
69 patch.assert_not_called()
70
Alex Klein076841b2019-08-29 15:19:39 -060071 def testMockCall(self):
72 """Sanity check that a mock call does not execute any logic."""
73 patch = self.PatchObject(sysroot_service, 'Create')
74 request = self._InputProto()
75 response = self._OutputProto()
76
77 rc = sysroot_controller.Create(request, response, self.mock_call_config)
78
79 patch.assert_not_called()
80 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
81
82 def testMockError(self):
83 """Sanity check that a mock error does not execute any logic."""
84 patch = self.PatchObject(sysroot_service, 'Create')
85 request = self._InputProto()
86 response = self._OutputProto()
87
88 rc = sysroot_controller.Create(request, response, self.mock_error_config)
89
90 patch.assert_not_called()
91 self.assertEqual(controller.RETURN_CODE_UNRECOVERABLE, rc)
92
Alex Kleinda35fcf2019-03-07 16:01:15 -070093 def testArgumentValidation(self):
94 """Test the input argument validation."""
95 # Error when no name provided.
96 in_proto = self._InputProto()
97 out_proto = self._OutputProto()
98 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060099 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700100
101 # Valid when board passed.
102 result = sysroot_lib.Sysroot('/sysroot/path')
103 patch = self.PatchObject(sysroot_service, 'Create', return_value=result)
104 in_proto = self._InputProto('board')
105 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600106 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700107 patch.assert_called_once()
108
109 def testArgumentHandling(self):
110 """Test the arguments get processed and passed correctly."""
111 sysroot_path = '/sysroot/path'
112
113 sysroot = sysroot_lib.Sysroot(sysroot_path)
Alex Kleind066b0f2022-07-28 08:47:35 -0600114 create_patch = self.PatchObject(
115 sysroot_service, 'Create', return_value=sysroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700116 rc_patch = self.PatchObject(sysroot_service, 'SetupBoardRunConfig')
117
118 # Default values.
119 board = 'board'
120 profile = None
121 force = False
122 upgrade_chroot = True
Alex Kleind066b0f2022-07-28 08:47:35 -0600123 in_proto = self._InputProto(
124 build_target=board,
125 profile=profile,
126 replace=force,
127 current=not upgrade_chroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700128 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600129 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700130
131 # Default value checks.
Alex Kleind066b0f2022-07-28 08:47:35 -0600132 rc_patch.assert_called_with(
Alex Kleineaa48532022-07-28 08:51:32 -0600133 force=force,
134 upgrade_chroot=upgrade_chroot,
135 package_indexes=[],
136 backtrack=sysroot_controller.DEFAULT_BACKTRACK,
137 )
Alex Kleinda35fcf2019-03-07 16:01:15 -0700138 self.assertEqual(board, out_proto.sysroot.build_target.name)
139 self.assertEqual(sysroot_path, out_proto.sysroot.path)
140
141 # Not default values.
142 create_patch.reset_mock()
143 board = 'board'
144 profile = 'profile'
145 force = True
146 upgrade_chroot = False
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600147 package_indexes = [
148 common_pb2.PackageIndexInfo(
Alex Kleind066b0f2022-07-28 08:47:35 -0600149 snapshot_sha='SHA',
150 snapshot_number=5,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600151 build_target=common_pb2.BuildTarget(name=board),
Alex Kleind066b0f2022-07-28 08:47:35 -0600152 location='LOCATION',
153 profile=common_pb2.Profile(name=profile)),
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600154 common_pb2.PackageIndexInfo(
Alex Kleind066b0f2022-07-28 08:47:35 -0600155 snapshot_sha='SHA2',
156 snapshot_number=4,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600157 build_target=common_pb2.BuildTarget(name=board),
Alex Kleind066b0f2022-07-28 08:47:35 -0600158 location='LOCATION2',
159 profile=common_pb2.Profile(name=profile))
160 ]
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600161
Alex Kleind066b0f2022-07-28 08:47:35 -0600162 in_proto = self._InputProto(
163 build_target=board,
164 profile=profile,
165 replace=force,
166 current=not upgrade_chroot,
167 package_indexes=package_indexes)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700168 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600169 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700170
171 # Not default value checks.
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600172 rc_patch.assert_called_with(
Alex Kleind066b0f2022-07-28 08:47:35 -0600173 force=force,
174 package_indexes=[
175 binpkg.PackageIndexInfo.from_protobuf(x) for x in package_indexes
176 ],
Alex Kleineaa48532022-07-28 08:51:32 -0600177 upgrade_chroot=upgrade_chroot,
178 backtrack=sysroot_controller.DEFAULT_BACKTRACK,
179 )
Alex Kleinda35fcf2019-03-07 16:01:15 -0700180 self.assertEqual(board, out_proto.sysroot.build_target.name)
181 self.assertEqual(sysroot_path, out_proto.sysroot.path)
182
183
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700184class GenerateArchiveTest(cros_test_lib.MockTempDirTestCase,
185 api_config.ApiConfigMixin):
186 """GenerateArchive function tests."""
187
188 def setUp(self):
189 self.chroot_path = '/path/to/chroot'
190 self.board = 'board'
191
192 def _InputProto(self, build_target=None, chroot_path=None, pkg_list=None):
193 """Helper to build and input proto instance."""
194 # pkg_list will be a list of category/package strings such as
195 # ['virtual/target-fuzzers'].
196 if pkg_list:
197 package_list = []
198 for pkg in pkg_list:
199 pkg_string_parts = pkg.split('/')
Alex Klein18a60af2020-06-11 12:08:47 -0600200 package_info_msg = common_pb2.PackageInfo(
Alex Kleind066b0f2022-07-28 08:47:35 -0600201 category=pkg_string_parts[0], package_name=pkg_string_parts[1])
Alex Klein18a60af2020-06-11 12:08:47 -0600202 package_list.append(package_info_msg)
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700203 else:
204 package_list = []
205
206 return sysroot_pb2.SysrootGenerateArchiveRequest(
207 build_target={'name': build_target},
208 chroot={'path': chroot_path},
209 packages=package_list)
210
211 def _OutputProto(self):
212 """Helper to build output proto instance."""
213 return sysroot_pb2.SysrootGenerateArchiveResponse()
214
215 def testValidateOnly(self):
216 """Sanity check that a validate only call does not execute any logic."""
217 patch = self.PatchObject(sysroot_service, 'GenerateArchive')
218
Alex Kleind066b0f2022-07-28 08:47:35 -0600219 in_proto = self._InputProto(
220 build_target=self.board,
221 chroot_path=self.chroot_path,
222 pkg_list=['virtual/target-fuzzers'])
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700223 sysroot_controller.GenerateArchive(in_proto, self._OutputProto(),
224 self.validate_only_config)
225 patch.assert_not_called()
226
227 def testMockCall(self):
228 """Sanity check that a mock call does not execute any logic."""
229 patch = self.PatchObject(sysroot_service, 'GenerateArchive')
230
Alex Kleind066b0f2022-07-28 08:47:35 -0600231 in_proto = self._InputProto(
232 build_target=self.board,
233 chroot_path=self.chroot_path,
234 pkg_list=['virtual/target-fuzzers'])
235 sysroot_controller.GenerateArchive(in_proto, self._OutputProto(),
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700236 self.mock_call_config)
237 patch.assert_not_called()
238
239 def testArgumentValidation(self):
240 """Test the input argument validation."""
241 # Error when no build target provided.
242 in_proto = self._InputProto()
243 out_proto = self._OutputProto()
244 with self.assertRaises(cros_build_lib.DieSystemExit):
245 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
246
247 # Error when packages is not specified.
Alex Kleind066b0f2022-07-28 08:47:35 -0600248 in_proto = self._InputProto(
249 build_target='board', chroot_path=self.chroot_path)
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700250 with self.assertRaises(cros_build_lib.DieSystemExit):
251 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
252
253 # Valid when board, chroot path, and package are specified.
Alex Kleind066b0f2022-07-28 08:47:35 -0600254 patch = self.PatchObject(
255 sysroot_service,
256 'GenerateArchive',
257 return_value='/path/to/sysroot/tar.bz')
258 in_proto = self._InputProto(
259 build_target='board',
260 chroot_path=self.chroot_path,
261 pkg_list=['virtual/target-fuzzers'])
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700262 out_proto = self._OutputProto()
263 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
264 patch.assert_called_once()
265
266
Alex Klein231d2da2019-07-22 16:44:45 -0600267class InstallToolchainTest(cros_test_lib.MockTempDirTestCase,
268 api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -0700269 """Install toolchain function tests."""
270
271 def setUp(self):
272 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600273 # Avoid running the portageq command.
274 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleinda35fcf2019-03-07 16:01:15 -0700275 self.board = 'board'
276 self.sysroot = os.path.join(self.tempdir, 'board')
277 self.invalid_sysroot = os.path.join(self.tempdir, 'invalid', 'sysroot')
278 osutils.SafeMakedirs(self.sysroot)
Lizzy Presland7e23a612021-11-09 21:49:42 +0000279 # Set up portage log directory.
Lizzy Presland4c279832021-11-19 20:27:43 +0000280 self.target_sysroot = sysroot_lib.Sysroot(self.sysroot)
Alex Kleine1c4d4b2022-01-05 14:51:04 -0700281 self.portage_dir = os.path.join(self.tempdir, 'portage_logdir')
282 self.PatchObject(
283 sysroot_lib.Sysroot, 'portage_logdir', new=self.portage_dir)
Lizzy Presland7e23a612021-11-09 21:49:42 +0000284 osutils.SafeMakedirs(self.portage_dir)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700285
Alex Kleind066b0f2022-07-28 08:47:35 -0600286 def _InputProto(self,
287 build_target=None,
288 sysroot_path=None,
Alex Kleinda35fcf2019-03-07 16:01:15 -0700289 compile_source=False):
Alex Kleind4e1e422019-03-18 16:00:41 -0600290 """Helper to build an input proto instance."""
Alex Kleinda35fcf2019-03-07 16:01:15 -0700291 proto = sysroot_pb2.InstallToolchainRequest()
292 if build_target:
293 proto.sysroot.build_target.name = build_target
294 if sysroot_path:
295 proto.sysroot.path = sysroot_path
296 if compile_source:
297 proto.flags.compile_source = compile_source
298
299 return proto
300
301 def _OutputProto(self):
302 """Helper to build output proto instance."""
303 return sysroot_pb2.InstallToolchainResponse()
304
Lizzy Preslandfc1db002022-05-06 18:19:49 +0000305 def _CreatePortageLogFile(self, log_path: Union[str, os.PathLike],
306 pkg_info: package_info.PackageInfo,
307 timestamp: datetime.datetime):
Lizzy Presland7e23a612021-11-09 21:49:42 +0000308 """Creates a log file for testing for individual packages built by Portage.
309
310 Args:
Lizzy Preslandfc1db002022-05-06 18:19:49 +0000311 log_path: The PORTAGE_LOGDIR path.
312 pkg_info: Package name used to name the log file.
313 timestamp: Timestamp used to name the file.
Lizzy Presland7e23a612021-11-09 21:49:42 +0000314 """
Lizzy Presland4c279832021-11-19 20:27:43 +0000315 path = os.path.join(log_path,
Lizzy Presland77741782021-12-13 19:46:42 +0000316 f'{pkg_info.category}:{pkg_info.pvr}:' \
Lizzy Presland7e23a612021-11-09 21:49:42 +0000317 f'{timestamp.strftime("%Y%m%d-%H%M%S")}.log')
Alex Kleind066b0f2022-07-28 08:47:35 -0600318 osutils.WriteFile(
319 path, f'Test log file for package {pkg_info.category}/'
320 f'{pkg_info.package} written to {path}')
Lizzy Presland7e23a612021-11-09 21:49:42 +0000321 return path
322
Alex Klein231d2da2019-07-22 16:44:45 -0600323 def testValidateOnly(self):
324 """Sanity check that a validate only call does not execute any logic."""
325 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
326
Alex Kleind066b0f2022-07-28 08:47:35 -0600327 in_proto = self._InputProto(
328 build_target=self.board, sysroot_path=self.sysroot)
Alex Klein231d2da2019-07-22 16:44:45 -0600329 sysroot_controller.InstallToolchain(in_proto, self._OutputProto(),
330 self.validate_only_config)
331 patch.assert_not_called()
332
Alex Klein076841b2019-08-29 15:19:39 -0600333 def testMockCall(self):
334 """Sanity check that a mock call does not execute any logic."""
335 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
336 request = self._InputProto()
337 response = self._OutputProto()
338
339 rc = sysroot_controller.InstallToolchain(request, response,
340 self.mock_call_config)
341
342 patch.assert_not_called()
343 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
344
345 def testMockError(self):
346 """Sanity check that a mock error does not execute any logic."""
347 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
348 request = self._InputProto()
349 response = self._OutputProto()
350
351 rc = sysroot_controller.InstallToolchain(request, response,
352 self.mock_error_config)
353
354 patch.assert_not_called()
355 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000356 self.assertTrue(response.failed_package_data)
Alex Klein076841b2019-08-29 15:19:39 -0600357
Alex Kleinda35fcf2019-03-07 16:01:15 -0700358 def testArgumentValidation(self):
359 """Test the argument validation."""
360 # Test errors on missing inputs.
361 out_proto = self._OutputProto()
362 # Both missing.
363 in_proto = self._InputProto()
364 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600365 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700366
367 # Sysroot path missing.
368 in_proto = self._InputProto(build_target=self.board)
369 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600370 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700371
372 # Build target name missing.
373 in_proto = self._InputProto(sysroot_path=self.sysroot)
374 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600375 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700376
377 # Both provided, but invalid sysroot path.
Alex Kleind066b0f2022-07-28 08:47:35 -0600378 in_proto = self._InputProto(
379 build_target=self.board, sysroot_path=self.invalid_sysroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700380 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600381 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700382
383 def testSuccessOutputHandling(self):
384 """Test the output is processed and recorded correctly."""
385 self.PatchObject(sysroot_service, 'InstallToolchain')
386 out_proto = self._OutputProto()
Alex Kleind066b0f2022-07-28 08:47:35 -0600387 in_proto = self._InputProto(
388 build_target=self.board, sysroot_path=self.sysroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700389
Alex Klein231d2da2019-07-22 16:44:45 -0600390 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
391 self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700392 self.assertFalse(rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000393 self.assertFalse(out_proto.failed_package_data)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700394
Alex Kleinda35fcf2019-03-07 16:01:15 -0700395 def testErrorOutputHandling(self):
396 """Test the error output is processed and recorded correctly."""
397 out_proto = self._OutputProto()
Alex Kleind066b0f2022-07-28 08:47:35 -0600398 in_proto = self._InputProto(
399 build_target=self.board, sysroot_path=self.sysroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700400
Lizzy Presland77741782021-12-13 19:46:42 +0000401 err_pkgs = ['cat/pkg-1.0-r1', 'cat2/pkg2-1.0-r1']
Alex Kleinea0c89e2021-09-09 15:17:35 -0600402 err_cpvs = [package_info.parse(pkg) for pkg in err_pkgs]
Alex Kleinda35fcf2019-03-07 16:01:15 -0700403 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
Lizzy Presland7e23a612021-11-09 21:49:42 +0000404
405 new_logs = {}
406 for i, pkg in enumerate(err_pkgs):
Lizzy Presland4c279832021-11-19 20:27:43 +0000407 self._CreatePortageLogFile(self.portage_dir, err_cpvs[i],
Lizzy Presland7e23a612021-11-09 21:49:42 +0000408 datetime.datetime(2021, 6, 9, 13, 37, 0))
Alex Kleind066b0f2022-07-28 08:47:35 -0600409 new_logs[pkg] = self._CreatePortageLogFile(
410 self.portage_dir, err_cpvs[i],
411 datetime.datetime(2021, 6, 9, 16, 20, 0))
Lizzy Presland7e23a612021-11-09 21:49:42 +0000412
Alex Kleind066b0f2022-07-28 08:47:35 -0600413 err = sysroot_lib.ToolchainInstallError(
Mike Frysinger112b67c2022-08-08 00:52:10 -0400414 'Error', cros_build_lib.CompletedProcess(), tc_info=err_cpvs)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700415 self.PatchObject(sysroot_service, 'InstallToolchain', side_effect=err)
416
Alex Klein231d2da2019-07-22 16:44:45 -0600417 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
418 self.api_config)
Alex Klein8cb365a2019-05-15 16:24:53 -0600419 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Lizzy Presland7e23a612021-11-09 21:49:42 +0000420 self.assertTrue(out_proto.failed_package_data)
421 # This needs to return 2 to indicate the available error response.
422 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
423 for data in out_proto.failed_package_data:
424 package = controller_util.deserialize_package_info(data.name)
425 cat_pkg = (data.name.category, data.name.package_name)
426 self.assertIn(cat_pkg, expected)
Lizzy Presland77741782021-12-13 19:46:42 +0000427 self.assertEqual(data.log_path.path, new_logs[package.cpvr])
Lizzy Presland7e23a612021-11-09 21:49:42 +0000428
Alex Kleind4e1e422019-03-18 16:00:41 -0600429
Alex Klein231d2da2019-07-22 16:44:45 -0600430class InstallPackagesTest(cros_test_lib.MockTempDirTestCase,
431 api_config.ApiConfigMixin):
Alex Kleind4e1e422019-03-18 16:00:41 -0600432 """InstallPackages tests."""
433
434 def setUp(self):
435 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600436 # Avoid running the portageq command.
437 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleind4e1e422019-03-18 16:00:41 -0600438 self.build_target = 'board'
439 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
440 osutils.SafeMakedirs(self.sysroot)
Lizzy Presland7e23a612021-11-09 21:49:42 +0000441 # Set up portage log directory.
Lizzy Presland4c279832021-11-19 20:27:43 +0000442 self.target_sysroot = sysroot_lib.Sysroot(self.sysroot)
Alex Kleine1c4d4b2022-01-05 14:51:04 -0700443 self.portage_dir = os.path.join(self.tempdir, 'portage_logdir')
444 self.PatchObject(
445 sysroot_lib.Sysroot, 'portage_logdir', new=self.portage_dir)
Lizzy Presland7e23a612021-11-09 21:49:42 +0000446 osutils.SafeMakedirs(self.portage_dir)
Michael Mortensen798ee192020-01-17 13:04:43 -0700447 # Set up goma directories.
448 self.goma_dir = os.path.join(self.tempdir, 'goma_dir')
449 osutils.SafeMakedirs(self.goma_dir)
450 self.goma_out_dir = os.path.join(self.tempdir, 'goma_out_dir')
451 osutils.SafeMakedirs(self.goma_out_dir)
Michael Mortensen4ccfb082020-01-22 16:24:03 -0700452 os.environ['GLOG_log_dir'] = self.goma_dir
Alex Kleind4e1e422019-03-18 16:00:41 -0600453
Alex Kleind066b0f2022-07-28 08:47:35 -0600454 def _InputProto(self,
455 build_target=None,
456 sysroot_path=None,
457 build_source=False,
458 goma_dir=None,
459 goma_log_dir=None,
460 goma_stats_file=None,
461 goma_counterz_file=None,
462 package_indexes=None,
463 packages=None):
Alex Kleind4e1e422019-03-18 16:00:41 -0600464 """Helper to build an input proto instance."""
465 instance = sysroot_pb2.InstallPackagesRequest()
466
467 if build_target:
468 instance.sysroot.build_target.name = build_target
469 if sysroot_path:
470 instance.sysroot.path = sysroot_path
471 if build_source:
472 instance.flags.build_source = build_source
Michael Mortensen798ee192020-01-17 13:04:43 -0700473 if goma_dir:
474 instance.goma_config.goma_dir = goma_dir
475 if goma_log_dir:
476 instance.goma_config.log_dir.dir = goma_log_dir
477 if goma_stats_file:
478 instance.goma_config.stats_file = goma_stats_file
479 if goma_counterz_file:
480 instance.goma_config.counterz_file = goma_counterz_file
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600481 if package_indexes:
482 instance.package_indexes.extend(package_indexes)
Alex Kleinca572ee2020-09-03 10:47:14 -0600483 if packages:
484 for pkg in packages:
Alex Kleinb397b792021-09-09 15:55:45 -0600485 pkg_info = package_info.parse(pkg)
486 pkg_info_msg = instance.packages.add()
487 controller_util.serialize_package_info(pkg_info, pkg_info_msg)
Alex Kleind4e1e422019-03-18 16:00:41 -0600488 return instance
489
490 def _OutputProto(self):
491 """Helper to build an empty output proto instance."""
492 return sysroot_pb2.InstallPackagesResponse()
493
Lizzy Preslandfc1db002022-05-06 18:19:49 +0000494 def _CreateGomaLogFile(self, goma_log_dir: Union[str, os.PathLike], name: str,
495 timestamp: datetime.datetime):
Michael Mortensen798ee192020-01-17 13:04:43 -0700496 """Creates a log file for testing.
497
498 Args:
Lizzy Preslandfc1db002022-05-06 18:19:49 +0000499 goma_log_dir: Directory where the file will be created.
500 name: Log file 'base' name that is combined with the timestamp.
501 timestamp: Timestamp that is written to the file.
Michael Mortensen798ee192020-01-17 13:04:43 -0700502 """
503 path = os.path.join(
504 goma_log_dir,
505 '%s.host.log.INFO.%s' % (name, timestamp.strftime('%Y%m%d-%H%M%S.%f')))
506 osutils.WriteFile(
Alex Kleind066b0f2022-07-28 08:47:35 -0600507 path, timestamp.strftime('Goma log file created at: %Y/%m/%d %H:%M:%S'))
Michael Mortensen798ee192020-01-17 13:04:43 -0700508
Lizzy Preslandfc1db002022-05-06 18:19:49 +0000509 def _CreatePortageLogFile(self, log_path: Union[str, os.PathLike],
510 pkg_info: package_info.PackageInfo,
511 timestamp: datetime.datetime):
Lizzy Presland7e23a612021-11-09 21:49:42 +0000512 """Creates a log file for testing for individual packages built by Portage.
513
514 Args:
Lizzy Preslandfc1db002022-05-06 18:19:49 +0000515 log_path: The PORTAGE_LOGDIR path.
516 pkg_info: Package name used to name the log file.
517 timestamp: Timestamp used to name the file.
Lizzy Presland7e23a612021-11-09 21:49:42 +0000518 """
Lizzy Presland4c279832021-11-19 20:27:43 +0000519 path = os.path.join(log_path,
Lizzy Presland77741782021-12-13 19:46:42 +0000520 f'{pkg_info.category}:{pkg_info.pvr}:' \
Lizzy Presland7e23a612021-11-09 21:49:42 +0000521 f'{timestamp.strftime("%Y%m%d-%H%M%S")}.log')
Alex Kleind066b0f2022-07-28 08:47:35 -0600522 osutils.WriteFile(
523 path, f'Test log file for package {pkg_info.category}/'
524 f'{pkg_info.package} written to {path}')
Lizzy Presland7e23a612021-11-09 21:49:42 +0000525 return path
526
Alex Klein231d2da2019-07-22 16:44:45 -0600527 def testValidateOnly(self):
528 """Sanity check that a validate only call does not execute any logic."""
529 patch = self.PatchObject(sysroot_service, 'BuildPackages')
530
Alex Kleind066b0f2022-07-28 08:47:35 -0600531 in_proto = self._InputProto(
532 build_target=self.build_target, sysroot_path=self.sysroot)
Alex Klein231d2da2019-07-22 16:44:45 -0600533 sysroot_controller.InstallPackages(in_proto, self._OutputProto(),
534 self.validate_only_config)
535 patch.assert_not_called()
536
Alex Klein076841b2019-08-29 15:19:39 -0600537 def testMockCall(self):
538 """Sanity check that a mock call does not execute any logic."""
539 patch = self.PatchObject(sysroot_service, 'BuildPackages')
540 request = self._InputProto()
541 response = self._OutputProto()
542
543 rc = sysroot_controller.InstallPackages(request, response,
544 self.mock_call_config)
545
546 patch.assert_not_called()
547 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
548
549 def testMockError(self):
550 """Sanity check that a mock error does not execute any logic."""
551 patch = self.PatchObject(sysroot_service, 'BuildPackages')
552 request = self._InputProto()
553 response = self._OutputProto()
554
555 rc = sysroot_controller.InstallPackages(request, response,
556 self.mock_error_config)
557
558 patch.assert_not_called()
559 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000560 self.assertTrue(response.failed_package_data)
Alex Klein076841b2019-08-29 15:19:39 -0600561
Alex Kleind4e1e422019-03-18 16:00:41 -0600562 def testArgumentValidationAllMissing(self):
563 """Test missing all arguments."""
564 out_proto = self._OutputProto()
565 in_proto = self._InputProto()
566 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600567 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600568
569 def testArgumentValidationNoSysroot(self):
570 """Test missing sysroot path."""
571 out_proto = self._OutputProto()
572 in_proto = self._InputProto(build_target=self.build_target)
573 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600574 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600575
576 def testArgumentValidationNoBuildTarget(self):
577 """Test missing build target name."""
578 out_proto = self._OutputProto()
579 in_proto = self._InputProto(sysroot_path=self.sysroot)
580 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600581 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600582
583 def testArgumentValidationInvalidSysroot(self):
584 """Test sysroot that hasn't had the toolchain installed."""
585 out_proto = self._OutputProto()
Alex Kleind066b0f2022-07-28 08:47:35 -0600586 in_proto = self._InputProto(
587 build_target=self.build_target, sysroot_path=self.sysroot)
588 self.PatchObject(
589 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=False)
Alex Kleind4e1e422019-03-18 16:00:41 -0600590 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600591 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600592
Alex Kleinca572ee2020-09-03 10:47:14 -0600593 def testArgumentValidationInvalidPackage(self):
594 out_proto = self._OutputProto()
Alex Kleind066b0f2022-07-28 08:47:35 -0600595 in_proto = self._InputProto(
596 build_target=self.build_target,
597 sysroot_path=self.sysroot,
598 packages=['package-1.0.0-r2'])
Alex Kleinca572ee2020-09-03 10:47:14 -0600599 with self.assertRaises(cros_build_lib.DieSystemExit):
600 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
601
Alex Kleind4e1e422019-03-18 16:00:41 -0600602 def testSuccessOutputHandling(self):
603 """Test successful call output handling."""
604 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600605 self.PatchObject(
606 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
Alex Kleind4e1e422019-03-18 16:00:41 -0600607
Alex Kleind066b0f2022-07-28 08:47:35 -0600608 in_proto = self._InputProto(
609 build_target=self.build_target, sysroot_path=self.sysroot)
Alex Kleind4e1e422019-03-18 16:00:41 -0600610 out_proto = self._OutputProto()
611 self.PatchObject(sysroot_service, 'BuildPackages')
612
Alex Klein231d2da2019-07-22 16:44:45 -0600613 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
614 self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600615 self.assertFalse(rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000616 self.assertFalse(out_proto.failed_package_data)
Alex Kleind4e1e422019-03-18 16:00:41 -0600617
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600618 def testSuccessPackageIndexes(self):
619 """Test successful call with package_indexes."""
620 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600621 self.PatchObject(
622 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600623 package_indexes = [
624 common_pb2.PackageIndexInfo(
Alex Kleind066b0f2022-07-28 08:47:35 -0600625 snapshot_sha='SHA',
626 snapshot_number=5,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600627 build_target=common_pb2.BuildTarget(name='board'),
Alex Kleind066b0f2022-07-28 08:47:35 -0600628 location='LOCATION',
629 profile=common_pb2.Profile(name='profile')),
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600630 common_pb2.PackageIndexInfo(
Alex Kleind066b0f2022-07-28 08:47:35 -0600631 snapshot_sha='SHA2',
632 snapshot_number=4,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600633 build_target=common_pb2.BuildTarget(name='board'),
Alex Kleind066b0f2022-07-28 08:47:35 -0600634 location='LOCATION2',
635 profile=common_pb2.Profile(name='profile'))
636 ]
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600637
Alex Kleind066b0f2022-07-28 08:47:35 -0600638 in_proto = self._InputProto(
639 build_target=self.build_target,
640 sysroot_path=self.sysroot,
641 package_indexes=package_indexes)
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600642
643 out_proto = self._OutputProto()
644 rc_patch = self.PatchObject(sysroot_service, 'BuildPackagesRunConfig')
645 self.PatchObject(sysroot_service, 'BuildPackages')
646
647 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
648 self.api_config)
649 self.assertFalse(rc)
Alex Kleineb76da72021-03-19 10:43:09 -0600650 rc_patch.assert_called_with(
Cindy Lin7487daa2022-02-23 04:14:10 +0000651 use_any_chrome=False,
Alex Kleineb76da72021-03-19 10:43:09 -0600652 usepkg=True,
653 install_debug_symbols=True,
654 packages=[],
655 package_indexes=[
656 binpkg.PackageIndexInfo.from_protobuf(x) for x in package_indexes
657 ],
658 use_flags=[],
659 use_goma=False,
Joanna Wang1ec0c812021-11-17 17:41:27 -0800660 use_remoteexec=False,
Alex Kleineb76da72021-03-19 10:43:09 -0600661 incremental_build=False,
Alex Kleineaa48532022-07-28 08:51:32 -0600662 dryrun=False,
663 backtrack=sysroot_controller.DEFAULT_BACKTRACK,
664 )
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600665
Michael Mortensen798ee192020-01-17 13:04:43 -0700666 def testSuccessWithGomaLogs(self):
667 """Test successful call with goma."""
668 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
669 datetime.datetime(2018, 9, 21, 12, 0, 0))
670 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
671 datetime.datetime(2018, 9, 21, 12, 1, 0))
672 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
673 datetime.datetime(2018, 9, 21, 12, 2, 0))
674
675 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600676 self.PatchObject(
677 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
Michael Mortensen798ee192020-01-17 13:04:43 -0700678
Alex Kleind066b0f2022-07-28 08:47:35 -0600679 in_proto = self._InputProto(
680 build_target=self.build_target,
681 sysroot_path=self.sysroot,
682 goma_dir=self.goma_dir,
683 goma_log_dir=self.goma_out_dir)
Michael Mortensen798ee192020-01-17 13:04:43 -0700684
685 out_proto = self._OutputProto()
686 self.PatchObject(sysroot_service, 'BuildPackages')
687
688 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
689 self.api_config)
690 self.assertFalse(rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000691 self.assertFalse(out_proto.failed_package_data)
Michael Mortensen798ee192020-01-17 13:04:43 -0700692 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
693 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
694 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
Alex Kleind066b0f2022-07-28 08:47:35 -0600695 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'
696 ])
Michael Mortensen798ee192020-01-17 13:04:43 -0700697
698 def testSuccessWithGomaLogsAndStatsCounterzFiles(self):
699 """Test successful call with goma including stats and counterz files."""
700 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
701 datetime.datetime(2018, 9, 21, 12, 0, 0))
702 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
703 datetime.datetime(2018, 9, 21, 12, 1, 0))
704 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
705 datetime.datetime(2018, 9, 21, 12, 2, 0))
706 # Create stats and counterz files.
Alex Kleind066b0f2022-07-28 08:47:35 -0600707 osutils.WriteFile(
708 os.path.join(self.goma_dir, 'stats.binaryproto'),
709 'File: stats.binaryproto')
710 osutils.WriteFile(
711 os.path.join(self.goma_dir, 'counterz.binaryproto'),
712 'File: counterz.binaryproto')
Michael Mortensen798ee192020-01-17 13:04:43 -0700713
714 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600715 self.PatchObject(
716 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
Michael Mortensen798ee192020-01-17 13:04:43 -0700717
Alex Kleind066b0f2022-07-28 08:47:35 -0600718 in_proto = self._InputProto(
719 build_target=self.build_target,
720 sysroot_path=self.sysroot,
721 goma_dir=self.goma_dir,
722 goma_log_dir=self.goma_out_dir,
723 goma_stats_file='stats.binaryproto',
724 goma_counterz_file='counterz.binaryproto')
Michael Mortensen798ee192020-01-17 13:04:43 -0700725
726 out_proto = self._OutputProto()
727 self.PatchObject(sysroot_service, 'BuildPackages')
728
729 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
730 self.api_config)
731 self.assertFalse(rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000732 self.assertFalse(out_proto.failed_package_data)
Michael Mortensen798ee192020-01-17 13:04:43 -0700733 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
734 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
735 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
Alex Kleind066b0f2022-07-28 08:47:35 -0600736 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'
737 ])
Michael Mortensen798ee192020-01-17 13:04:43 -0700738 # Verify that the output dir has 5 files -- since there should be 3 log
739 # files, the stats file, and the counterz file.
740 output_files = os.listdir(self.goma_out_dir)
741 self.assertCountEqual(output_files, [
Alex Kleind066b0f2022-07-28 08:47:35 -0600742 'stats.binaryproto', 'counterz.binaryproto',
Michael Mortensen798ee192020-01-17 13:04:43 -0700743 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
744 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
Alex Kleind066b0f2022-07-28 08:47:35 -0600745 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'
746 ])
Michael Mortensen1c7439c2020-01-24 14:43:19 -0700747 self.assertEqual(out_proto.goma_artifacts.counterz_file,
748 'counterz.binaryproto')
Alex Kleind066b0f2022-07-28 08:47:35 -0600749 self.assertEqual(out_proto.goma_artifacts.stats_file, 'stats.binaryproto')
Michael Mortensen798ee192020-01-17 13:04:43 -0700750
751 def testFailureMissingGomaStatsCounterzFiles(self):
752 """Test successful call with goma including stats and counterz files."""
753 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
754 datetime.datetime(2018, 9, 21, 12, 0, 0))
755 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
756 datetime.datetime(2018, 9, 21, 12, 1, 0))
757 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
758 datetime.datetime(2018, 9, 21, 12, 2, 0))
759 # Note that stats and counterz files are not created, but are specified in
760 # the proto below.
761
762 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600763 self.PatchObject(
764 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
Michael Mortensen798ee192020-01-17 13:04:43 -0700765
Alex Kleind066b0f2022-07-28 08:47:35 -0600766 in_proto = self._InputProto(
767 build_target=self.build_target,
768 sysroot_path=self.sysroot,
769 goma_dir=self.goma_dir,
770 goma_log_dir=self.goma_out_dir,
771 goma_stats_file='stats.binaryproto',
772 goma_counterz_file='counterz.binaryproto')
Michael Mortensen798ee192020-01-17 13:04:43 -0700773
774 out_proto = self._OutputProto()
775 self.PatchObject(sysroot_service, 'BuildPackages')
776
Michael Mortensen1d6d5b02020-01-22 07:33:50 -0700777 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
778 self.api_config)
779 self.assertFalse(rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000780 self.assertFalse(out_proto.failed_package_data)
Michael Mortensen1d6d5b02020-01-22 07:33:50 -0700781 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
782 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
783 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
Alex Kleind066b0f2022-07-28 08:47:35 -0600784 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'
785 ])
Michael Mortensen1d6d5b02020-01-22 07:33:50 -0700786 self.assertFalse(out_proto.goma_artifacts.counterz_file)
787 self.assertFalse(out_proto.goma_artifacts.stats_file)
Michael Mortensen798ee192020-01-17 13:04:43 -0700788
Alex Kleind4e1e422019-03-18 16:00:41 -0600789 def testFailureOutputHandling(self):
790 """Test failed package handling."""
791 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600792 self.PatchObject(
793 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
Alex Kleind4e1e422019-03-18 16:00:41 -0600794
Alex Kleind066b0f2022-07-28 08:47:35 -0600795 in_proto = self._InputProto(
796 build_target=self.build_target, sysroot_path=self.sysroot)
Alex Kleind4e1e422019-03-18 16:00:41 -0600797 out_proto = self._OutputProto()
798
799 # Failed package info and expected list for verification.
Lizzy Presland77741782021-12-13 19:46:42 +0000800 err_pkgs = ['cat/pkg-1.0-r3', 'cat2/pkg2-1.0-r1']
Lizzy Presland7e23a612021-11-09 21:49:42 +0000801 err_cpvs = [package_info.parse(cpv) for cpv in err_pkgs]
Alex Kleind4e1e422019-03-18 16:00:41 -0600802 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
803
Lizzy Presland7e23a612021-11-09 21:49:42 +0000804 new_logs = {}
805 for i, pkg in enumerate(err_pkgs):
Lizzy Presland4c279832021-11-19 20:27:43 +0000806 self._CreatePortageLogFile(self.portage_dir, err_cpvs[i],
Lizzy Presland7e23a612021-11-09 21:49:42 +0000807 datetime.datetime(2021, 6, 9, 13, 37, 0))
Alex Kleind066b0f2022-07-28 08:47:35 -0600808 new_logs[pkg] = self._CreatePortageLogFile(
809 self.portage_dir, err_cpvs[i],
810 datetime.datetime(2021, 6, 9, 16, 20, 0))
Alex Kleind4e1e422019-03-18 16:00:41 -0600811 # Force error to be raised with the packages.
Alex Kleind066b0f2022-07-28 08:47:35 -0600812 error = sysroot_lib.PackageInstallError(
Mike Frysinger112b67c2022-08-08 00:52:10 -0400813 'Error', cros_build_lib.CompletedProcess(), packages=err_cpvs)
Alex Kleind4e1e422019-03-18 16:00:41 -0600814 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
815
Alex Klein231d2da2019-07-22 16:44:45 -0600816 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
817 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600818 # This needs to return 2 to indicate the available error response.
819 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Lizzy Presland7e23a612021-11-09 21:49:42 +0000820 for data in out_proto.failed_package_data:
821 package = controller_util.deserialize_package_info(data.name)
822 cat_pkg = (data.name.category, data.name.package_name)
823 self.assertIn(cat_pkg, expected)
Lizzy Presland77741782021-12-13 19:46:42 +0000824 self.assertEqual(data.log_path.path, new_logs[package.cpvr])
Lizzy Presland7e23a612021-11-09 21:49:42 +0000825
Alex Klein2557b4f2019-07-11 14:34:00 -0600826 def testNoPackageFailureOutputHandling(self):
827 """Test failure handling without packages to report."""
828 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600829 self.PatchObject(
830 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
Alex Klein2557b4f2019-07-11 14:34:00 -0600831
Alex Kleind066b0f2022-07-28 08:47:35 -0600832 in_proto = self._InputProto(
833 build_target=self.build_target, sysroot_path=self.sysroot)
Alex Klein2557b4f2019-07-11 14:34:00 -0600834 out_proto = self._OutputProto()
835
836 # Force error to be raised with no packages.
Alex Kleind066b0f2022-07-28 08:47:35 -0600837 error = sysroot_lib.PackageInstallError(
Mike Frysinger112b67c2022-08-08 00:52:10 -0400838 'Error', cros_build_lib.CompletedProcess(), packages=[])
Alex Klein2557b4f2019-07-11 14:34:00 -0600839 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
840
Alex Klein231d2da2019-07-22 16:44:45 -0600841 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
842 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600843 # All we really care about is it's not 0 or 2 (response available), so
844 # test for that rather than a specific return code.
845 self.assertTrue(rc)
846 self.assertNotEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE,
847 rc)