blob: 62a1f49ca7866880ff284e85b9f11bc8f51416e3 [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 Klein1699fab2022-09-08 08:46:06 -060027 """Create function tests."""
Alex Kleinda35fcf2019-03-07 16:01:15 -070028
Alex Klein1699fab2022-09-08 08:46:06 -060029 def _InputProto(
30 self,
31 build_target=None,
32 profile=None,
33 replace=False,
34 current=False,
35 package_indexes=None,
36 ):
37 """Helper to build and input proto instance."""
38 proto = sysroot_pb2.SysrootCreateRequest()
39 if build_target:
40 proto.build_target.name = build_target
41 if profile:
42 proto.profile.name = profile
43 if replace:
44 proto.flags.replace = replace
45 if current:
46 proto.flags.chroot_current = current
47 if package_indexes:
48 proto.package_indexes.extend(package_indexes)
Alex Kleinda35fcf2019-03-07 16:01:15 -070049
Alex Klein1699fab2022-09-08 08:46:06 -060050 return proto
Alex Kleinda35fcf2019-03-07 16:01:15 -070051
Alex Klein1699fab2022-09-08 08:46:06 -060052 def _OutputProto(self):
53 """Helper to build output proto instance."""
54 return sysroot_pb2.SysrootCreateResponse()
Alex Kleinda35fcf2019-03-07 16:01:15 -070055
Alex Klein1699fab2022-09-08 08:46:06 -060056 def testValidateOnly(self):
57 """Sanity check that a validate only call does not execute any logic."""
58 patch = self.PatchObject(sysroot_service, "Create")
Alex Klein231d2da2019-07-22 16:44:45 -060059
Alex Klein1699fab2022-09-08 08:46:06 -060060 board = "board"
61 profile = None
62 force = False
63 upgrade_chroot = True
64 in_proto = self._InputProto(
65 build_target=board,
66 profile=profile,
67 replace=force,
68 current=not upgrade_chroot,
69 )
70 sysroot_controller.Create(
71 in_proto, self._OutputProto(), self.validate_only_config
72 )
73 patch.assert_not_called()
Alex Klein231d2da2019-07-22 16:44:45 -060074
Alex Klein1699fab2022-09-08 08:46:06 -060075 def testMockCall(self):
76 """Sanity check that a mock call does not execute any logic."""
77 patch = self.PatchObject(sysroot_service, "Create")
78 request = self._InputProto()
79 response = self._OutputProto()
Alex Klein076841b2019-08-29 15:19:39 -060080
Alex Klein1699fab2022-09-08 08:46:06 -060081 rc = sysroot_controller.Create(request, response, self.mock_call_config)
Alex Klein076841b2019-08-29 15:19:39 -060082
Alex Klein1699fab2022-09-08 08:46:06 -060083 patch.assert_not_called()
84 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
Alex Klein076841b2019-08-29 15:19:39 -060085
Alex Klein1699fab2022-09-08 08:46:06 -060086 def testMockError(self):
87 """Sanity check that a mock error does not execute any logic."""
88 patch = self.PatchObject(sysroot_service, "Create")
89 request = self._InputProto()
90 response = self._OutputProto()
Alex Klein076841b2019-08-29 15:19:39 -060091
Alex Klein1699fab2022-09-08 08:46:06 -060092 rc = sysroot_controller.Create(
93 request, response, self.mock_error_config
94 )
Alex Klein076841b2019-08-29 15:19:39 -060095
Alex Klein1699fab2022-09-08 08:46:06 -060096 patch.assert_not_called()
97 self.assertEqual(controller.RETURN_CODE_UNRECOVERABLE, rc)
Alex Klein076841b2019-08-29 15:19:39 -060098
Alex Klein1699fab2022-09-08 08:46:06 -060099 def testArgumentValidation(self):
100 """Test the input argument validation."""
101 # Error when no name provided.
102 in_proto = self._InputProto()
103 out_proto = self._OutputProto()
104 with self.assertRaises(cros_build_lib.DieSystemExit):
105 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700106
Alex Klein1699fab2022-09-08 08:46:06 -0600107 # Valid when board passed.
108 result = sysroot_lib.Sysroot("/sysroot/path")
109 patch = self.PatchObject(sysroot_service, "Create", return_value=result)
110 in_proto = self._InputProto("board")
111 out_proto = self._OutputProto()
112 sysroot_controller.Create(in_proto, out_proto, self.api_config)
113 patch.assert_called_once()
Alex Kleinda35fcf2019-03-07 16:01:15 -0700114
Alex Klein1699fab2022-09-08 08:46:06 -0600115 def testArgumentHandling(self):
116 """Test the arguments get processed and passed correctly."""
117 sysroot_path = "/sysroot/path"
Alex Kleinda35fcf2019-03-07 16:01:15 -0700118
Alex Klein1699fab2022-09-08 08:46:06 -0600119 sysroot = sysroot_lib.Sysroot(sysroot_path)
120 create_patch = self.PatchObject(
121 sysroot_service, "Create", return_value=sysroot
122 )
123 rc_patch = self.PatchObject(sysroot_service, "SetupBoardRunConfig")
Alex Kleinda35fcf2019-03-07 16:01:15 -0700124
Alex Klein1699fab2022-09-08 08:46:06 -0600125 # Default values.
126 board = "board"
127 profile = None
128 force = False
129 upgrade_chroot = True
130 in_proto = self._InputProto(
131 build_target=board,
132 profile=profile,
133 replace=force,
134 current=not upgrade_chroot,
135 )
136 out_proto = self._OutputProto()
137 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700138
Alex Klein1699fab2022-09-08 08:46:06 -0600139 # Default value checks.
140 rc_patch.assert_called_with(
141 force=force,
142 upgrade_chroot=upgrade_chroot,
143 package_indexes=[],
144 backtrack=sysroot_controller.DEFAULT_BACKTRACK,
145 )
146 self.assertEqual(board, out_proto.sysroot.build_target.name)
147 self.assertEqual(sysroot_path, out_proto.sysroot.path)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700148
Alex Klein1699fab2022-09-08 08:46:06 -0600149 # Not default values.
150 create_patch.reset_mock()
151 board = "board"
152 profile = "profile"
153 force = True
154 upgrade_chroot = False
155 package_indexes = [
156 common_pb2.PackageIndexInfo(
157 snapshot_sha="SHA",
158 snapshot_number=5,
159 build_target=common_pb2.BuildTarget(name=board),
160 location="LOCATION",
161 profile=common_pb2.Profile(name=profile),
162 ),
163 common_pb2.PackageIndexInfo(
164 snapshot_sha="SHA2",
165 snapshot_number=4,
166 build_target=common_pb2.BuildTarget(name=board),
167 location="LOCATION2",
168 profile=common_pb2.Profile(name=profile),
169 ),
170 ]
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600171
Alex Klein1699fab2022-09-08 08:46:06 -0600172 in_proto = self._InputProto(
173 build_target=board,
174 profile=profile,
175 replace=force,
176 current=not upgrade_chroot,
177 package_indexes=package_indexes,
178 )
179 out_proto = self._OutputProto()
180 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700181
Alex Klein1699fab2022-09-08 08:46:06 -0600182 # Not default value checks.
183 rc_patch.assert_called_with(
184 force=force,
185 package_indexes=[
186 binpkg.PackageIndexInfo.from_protobuf(x)
187 for x in package_indexes
188 ],
189 upgrade_chroot=upgrade_chroot,
190 backtrack=sysroot_controller.DEFAULT_BACKTRACK,
191 )
192 self.assertEqual(board, out_proto.sysroot.build_target.name)
193 self.assertEqual(sysroot_path, out_proto.sysroot.path)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700194
195
Alex Klein1699fab2022-09-08 08:46:06 -0600196class GenerateArchiveTest(
197 cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin
198):
199 """GenerateArchive function tests."""
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700200
Alex Klein1699fab2022-09-08 08:46:06 -0600201 def setUp(self):
202 self.chroot_path = "/path/to/chroot"
203 self.board = "board"
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700204
Alex Klein1699fab2022-09-08 08:46:06 -0600205 def _InputProto(self, build_target=None, chroot_path=None, pkg_list=None):
206 """Helper to build and input proto instance."""
207 # pkg_list will be a list of category/package strings such as
208 # ['virtual/target-fuzzers'].
209 if pkg_list:
210 package_list = []
211 for pkg in pkg_list:
212 pkg_string_parts = pkg.split("/")
213 package_info_msg = common_pb2.PackageInfo(
214 category=pkg_string_parts[0],
215 package_name=pkg_string_parts[1],
216 )
217 package_list.append(package_info_msg)
218 else:
219 package_list = []
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700220
Alex Klein1699fab2022-09-08 08:46:06 -0600221 return sysroot_pb2.SysrootGenerateArchiveRequest(
222 build_target={"name": build_target},
223 chroot={"path": chroot_path},
224 packages=package_list,
225 )
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700226
Alex Klein1699fab2022-09-08 08:46:06 -0600227 def _OutputProto(self):
228 """Helper to build output proto instance."""
229 return sysroot_pb2.SysrootGenerateArchiveResponse()
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700230
Alex Klein1699fab2022-09-08 08:46:06 -0600231 def testValidateOnly(self):
232 """Sanity check that a validate only call does not execute any logic."""
233 patch = self.PatchObject(sysroot_service, "GenerateArchive")
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700234
Alex Klein1699fab2022-09-08 08:46:06 -0600235 in_proto = self._InputProto(
236 build_target=self.board,
237 chroot_path=self.chroot_path,
238 pkg_list=["virtual/target-fuzzers"],
239 )
240 sysroot_controller.GenerateArchive(
241 in_proto, self._OutputProto(), self.validate_only_config
242 )
243 patch.assert_not_called()
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700244
Alex Klein1699fab2022-09-08 08:46:06 -0600245 def testMockCall(self):
246 """Sanity check that a mock call does not execute any logic."""
247 patch = self.PatchObject(sysroot_service, "GenerateArchive")
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700248
Alex Klein1699fab2022-09-08 08:46:06 -0600249 in_proto = self._InputProto(
250 build_target=self.board,
251 chroot_path=self.chroot_path,
252 pkg_list=["virtual/target-fuzzers"],
253 )
254 sysroot_controller.GenerateArchive(
255 in_proto, self._OutputProto(), self.mock_call_config
256 )
257 patch.assert_not_called()
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700258
Alex Klein1699fab2022-09-08 08:46:06 -0600259 def testArgumentValidation(self):
260 """Test the input argument validation."""
261 # Error when no build target provided.
262 in_proto = self._InputProto()
263 out_proto = self._OutputProto()
264 with self.assertRaises(cros_build_lib.DieSystemExit):
265 sysroot_controller.GenerateArchive(
266 in_proto, out_proto, self.api_config
267 )
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700268
Alex Klein1699fab2022-09-08 08:46:06 -0600269 # Error when packages is not specified.
270 in_proto = self._InputProto(
271 build_target="board", chroot_path=self.chroot_path
272 )
273 with self.assertRaises(cros_build_lib.DieSystemExit):
274 sysroot_controller.GenerateArchive(
275 in_proto, out_proto, self.api_config
276 )
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700277
Alex Klein1699fab2022-09-08 08:46:06 -0600278 # Valid when board, chroot path, and package are specified.
279 patch = self.PatchObject(
280 sysroot_service,
281 "GenerateArchive",
282 return_value="/path/to/sysroot/tar.bz",
283 )
284 in_proto = self._InputProto(
285 build_target="board",
286 chroot_path=self.chroot_path,
287 pkg_list=["virtual/target-fuzzers"],
288 )
289 out_proto = self._OutputProto()
290 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
291 patch.assert_called_once()
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700292
293
Alex Klein1699fab2022-09-08 08:46:06 -0600294class InstallToolchainTest(
295 cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin
296):
297 """Install toolchain function tests."""
Alex Kleinda35fcf2019-03-07 16:01:15 -0700298
Alex Klein1699fab2022-09-08 08:46:06 -0600299 def setUp(self):
300 self.PatchObject(cros_build_lib, "IsInsideChroot", return_value=True)
301 # Avoid running the portageq command.
302 self.PatchObject(sysroot_controller, "_LogBinhost")
303 self.board = "board"
304 self.sysroot = os.path.join(self.tempdir, "board")
305 self.invalid_sysroot = os.path.join(self.tempdir, "invalid", "sysroot")
306 osutils.SafeMakedirs(self.sysroot)
307 # Set up portage log directory.
308 self.target_sysroot = sysroot_lib.Sysroot(self.sysroot)
309 self.portage_dir = os.path.join(self.tempdir, "portage_logdir")
310 self.PatchObject(
311 sysroot_lib.Sysroot, "portage_logdir", new=self.portage_dir
312 )
313 osutils.SafeMakedirs(self.portage_dir)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700314
Alex Klein1699fab2022-09-08 08:46:06 -0600315 def _InputProto(
316 self, build_target=None, sysroot_path=None, compile_source=False
317 ):
318 """Helper to build an input proto instance."""
319 proto = sysroot_pb2.InstallToolchainRequest()
320 if build_target:
321 proto.sysroot.build_target.name = build_target
322 if sysroot_path:
323 proto.sysroot.path = sysroot_path
324 if compile_source:
325 proto.flags.compile_source = compile_source
Alex Kleinda35fcf2019-03-07 16:01:15 -0700326
Alex Klein1699fab2022-09-08 08:46:06 -0600327 return proto
Alex Kleinda35fcf2019-03-07 16:01:15 -0700328
Alex Klein1699fab2022-09-08 08:46:06 -0600329 def _OutputProto(self):
330 """Helper to build output proto instance."""
331 return sysroot_pb2.InstallToolchainResponse()
Alex Kleinda35fcf2019-03-07 16:01:15 -0700332
Alex Klein1699fab2022-09-08 08:46:06 -0600333 def _CreatePortageLogFile(
334 self,
335 log_path: Union[str, os.PathLike],
336 pkg_info: package_info.PackageInfo,
337 timestamp: datetime.datetime,
338 ):
339 """Creates a log file for testing for individual packages built by Portage.
Lizzy Presland7e23a612021-11-09 21:49:42 +0000340
Alex Klein1699fab2022-09-08 08:46:06 -0600341 Args:
342 log_path: The PORTAGE_LOGDIR path.
343 pkg_info: Package name used to name the log file.
344 timestamp: Timestamp used to name the file.
345 """
346 path = os.path.join(
347 log_path,
348 f"{pkg_info.category}:{pkg_info.pvr}:"
349 f'{timestamp.strftime("%Y%m%d-%H%M%S")}.log',
350 )
351 osutils.WriteFile(
352 path,
353 f"Test log file for package {pkg_info.category}/"
354 f"{pkg_info.package} written to {path}",
355 )
356 return path
Lizzy Presland7e23a612021-11-09 21:49:42 +0000357
Alex Klein1699fab2022-09-08 08:46:06 -0600358 def testValidateOnly(self):
359 """Sanity check that a validate only call does not execute any logic."""
360 patch = self.PatchObject(sysroot_service, "InstallToolchain")
Alex Klein231d2da2019-07-22 16:44:45 -0600361
Alex Klein1699fab2022-09-08 08:46:06 -0600362 in_proto = self._InputProto(
363 build_target=self.board, sysroot_path=self.sysroot
364 )
365 sysroot_controller.InstallToolchain(
366 in_proto, self._OutputProto(), self.validate_only_config
367 )
368 patch.assert_not_called()
Alex Klein231d2da2019-07-22 16:44:45 -0600369
Alex Klein1699fab2022-09-08 08:46:06 -0600370 def testMockCall(self):
371 """Sanity check that a mock call does not execute any logic."""
372 patch = self.PatchObject(sysroot_service, "InstallToolchain")
373 request = self._InputProto()
374 response = self._OutputProto()
Alex Klein076841b2019-08-29 15:19:39 -0600375
Alex Klein1699fab2022-09-08 08:46:06 -0600376 rc = sysroot_controller.InstallToolchain(
377 request, response, self.mock_call_config
378 )
Alex Klein076841b2019-08-29 15:19:39 -0600379
Alex Klein1699fab2022-09-08 08:46:06 -0600380 patch.assert_not_called()
381 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
Alex Klein076841b2019-08-29 15:19:39 -0600382
Alex Klein1699fab2022-09-08 08:46:06 -0600383 def testMockError(self):
384 """Sanity check that a mock error does not execute any logic."""
385 patch = self.PatchObject(sysroot_service, "InstallToolchain")
386 request = self._InputProto()
387 response = self._OutputProto()
Alex Klein076841b2019-08-29 15:19:39 -0600388
Alex Klein1699fab2022-09-08 08:46:06 -0600389 rc = sysroot_controller.InstallToolchain(
390 request, response, self.mock_error_config
391 )
Alex Klein076841b2019-08-29 15:19:39 -0600392
Alex Klein1699fab2022-09-08 08:46:06 -0600393 patch.assert_not_called()
394 self.assertEqual(
395 controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc
396 )
397 self.assertTrue(response.failed_package_data)
Alex Klein076841b2019-08-29 15:19:39 -0600398
Alex Klein1699fab2022-09-08 08:46:06 -0600399 def testArgumentValidation(self):
400 """Test the argument validation."""
401 # Test errors on missing inputs.
402 out_proto = self._OutputProto()
403 # Both missing.
404 in_proto = self._InputProto()
405 with self.assertRaises(cros_build_lib.DieSystemExit):
406 sysroot_controller.InstallToolchain(
407 in_proto, out_proto, self.api_config
408 )
Alex Kleinda35fcf2019-03-07 16:01:15 -0700409
Alex Klein1699fab2022-09-08 08:46:06 -0600410 # Sysroot path missing.
411 in_proto = self._InputProto(build_target=self.board)
412 with self.assertRaises(cros_build_lib.DieSystemExit):
413 sysroot_controller.InstallToolchain(
414 in_proto, out_proto, self.api_config
415 )
Alex Kleinda35fcf2019-03-07 16:01:15 -0700416
Alex Klein1699fab2022-09-08 08:46:06 -0600417 # Build target name missing.
418 in_proto = self._InputProto(sysroot_path=self.sysroot)
419 with self.assertRaises(cros_build_lib.DieSystemExit):
420 sysroot_controller.InstallToolchain(
421 in_proto, out_proto, self.api_config
422 )
Alex Kleinda35fcf2019-03-07 16:01:15 -0700423
Alex Klein1699fab2022-09-08 08:46:06 -0600424 # Both provided, but invalid sysroot path.
425 in_proto = self._InputProto(
426 build_target=self.board, sysroot_path=self.invalid_sysroot
427 )
428 with self.assertRaises(cros_build_lib.DieSystemExit):
429 sysroot_controller.InstallToolchain(
430 in_proto, out_proto, self.api_config
431 )
Alex Kleinda35fcf2019-03-07 16:01:15 -0700432
Alex Klein1699fab2022-09-08 08:46:06 -0600433 def testSuccessOutputHandling(self):
434 """Test the output is processed and recorded correctly."""
435 self.PatchObject(sysroot_service, "InstallToolchain")
436 out_proto = self._OutputProto()
437 in_proto = self._InputProto(
438 build_target=self.board, sysroot_path=self.sysroot
439 )
Alex Kleinda35fcf2019-03-07 16:01:15 -0700440
Alex Klein1699fab2022-09-08 08:46:06 -0600441 rc = sysroot_controller.InstallToolchain(
442 in_proto, out_proto, self.api_config
443 )
444 self.assertFalse(rc)
445 self.assertFalse(out_proto.failed_package_data)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700446
Alex Klein1699fab2022-09-08 08:46:06 -0600447 def testErrorOutputHandling(self):
448 """Test the error output is processed and recorded correctly."""
449 out_proto = self._OutputProto()
450 in_proto = self._InputProto(
451 build_target=self.board, sysroot_path=self.sysroot
452 )
Alex Kleinda35fcf2019-03-07 16:01:15 -0700453
Alex Klein1699fab2022-09-08 08:46:06 -0600454 err_pkgs = ["cat/pkg-1.0-r1", "cat2/pkg2-1.0-r1"]
455 err_cpvs = [package_info.parse(pkg) for pkg in err_pkgs]
456 expected = [("cat", "pkg"), ("cat2", "pkg2")]
Lizzy Presland7e23a612021-11-09 21:49:42 +0000457
Alex Klein1699fab2022-09-08 08:46:06 -0600458 new_logs = {}
459 for i, pkg in enumerate(err_pkgs):
460 self._CreatePortageLogFile(
461 self.portage_dir,
462 err_cpvs[i],
463 datetime.datetime(2021, 6, 9, 13, 37, 0),
464 )
465 new_logs[pkg] = self._CreatePortageLogFile(
466 self.portage_dir,
467 err_cpvs[i],
468 datetime.datetime(2021, 6, 9, 16, 20, 0),
469 )
Lizzy Presland7e23a612021-11-09 21:49:42 +0000470
Alex Klein1699fab2022-09-08 08:46:06 -0600471 err = sysroot_lib.ToolchainInstallError(
472 "Error", cros_build_lib.CompletedProcess(), tc_info=err_cpvs
473 )
474 self.PatchObject(sysroot_service, "InstallToolchain", side_effect=err)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700475
Alex Klein1699fab2022-09-08 08:46:06 -0600476 rc = sysroot_controller.InstallToolchain(
477 in_proto, out_proto, self.api_config
478 )
479 self.assertEqual(
480 controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc
481 )
482 self.assertTrue(out_proto.failed_package_data)
483 # This needs to return 2 to indicate the available error response.
484 self.assertEqual(
485 controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc
486 )
487 for data in out_proto.failed_package_data:
488 package = controller_util.deserialize_package_info(data.name)
489 cat_pkg = (data.name.category, data.name.package_name)
490 self.assertIn(cat_pkg, expected)
491 self.assertEqual(data.log_path.path, new_logs[package.cpvr])
Lizzy Presland7e23a612021-11-09 21:49:42 +0000492
Alex Kleind4e1e422019-03-18 16:00:41 -0600493
Alex Klein1699fab2022-09-08 08:46:06 -0600494class InstallPackagesTest(
495 cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin
496):
497 """InstallPackages tests."""
Alex Kleind4e1e422019-03-18 16:00:41 -0600498
Alex Klein1699fab2022-09-08 08:46:06 -0600499 def setUp(self):
500 self.PatchObject(cros_build_lib, "IsInsideChroot", return_value=True)
501 # Avoid running the portageq command.
502 self.PatchObject(sysroot_controller, "_LogBinhost")
503 self.build_target = "board"
504 self.sysroot = os.path.join(self.tempdir, "build", "board")
505 osutils.SafeMakedirs(self.sysroot)
506 # Set up portage log directory.
507 self.target_sysroot = sysroot_lib.Sysroot(self.sysroot)
508 self.portage_dir = os.path.join(self.tempdir, "portage_logdir")
509 self.PatchObject(
510 sysroot_lib.Sysroot, "portage_logdir", new=self.portage_dir
511 )
512 osutils.SafeMakedirs(self.portage_dir)
513 # Set up goma directories.
514 self.goma_dir = os.path.join(self.tempdir, "goma_dir")
515 osutils.SafeMakedirs(self.goma_dir)
516 self.goma_out_dir = os.path.join(self.tempdir, "goma_out_dir")
517 osutils.SafeMakedirs(self.goma_out_dir)
518 os.environ["GLOG_log_dir"] = self.goma_dir
Alex Kleind4e1e422019-03-18 16:00:41 -0600519
Alex Klein1699fab2022-09-08 08:46:06 -0600520 def _InputProto(
521 self,
522 build_target=None,
523 sysroot_path=None,
524 build_source=False,
525 goma_dir=None,
526 goma_log_dir=None,
527 goma_stats_file=None,
528 goma_counterz_file=None,
529 package_indexes=None,
530 packages=None,
531 ):
532 """Helper to build an input proto instance."""
533 instance = sysroot_pb2.InstallPackagesRequest()
Alex Kleind4e1e422019-03-18 16:00:41 -0600534
Alex Klein1699fab2022-09-08 08:46:06 -0600535 if build_target:
536 instance.sysroot.build_target.name = build_target
537 if sysroot_path:
538 instance.sysroot.path = sysroot_path
539 if build_source:
540 instance.flags.build_source = build_source
541 if goma_dir:
542 instance.goma_config.goma_dir = goma_dir
543 if goma_log_dir:
544 instance.goma_config.log_dir.dir = goma_log_dir
545 if goma_stats_file:
546 instance.goma_config.stats_file = goma_stats_file
547 if goma_counterz_file:
548 instance.goma_config.counterz_file = goma_counterz_file
549 if package_indexes:
550 instance.package_indexes.extend(package_indexes)
551 if packages:
552 for pkg in packages:
553 pkg_info = package_info.parse(pkg)
554 pkg_info_msg = instance.packages.add()
555 controller_util.serialize_package_info(pkg_info, pkg_info_msg)
556 return instance
Alex Kleind4e1e422019-03-18 16:00:41 -0600557
Alex Klein1699fab2022-09-08 08:46:06 -0600558 def _OutputProto(self):
559 """Helper to build an empty output proto instance."""
560 return sysroot_pb2.InstallPackagesResponse()
Alex Kleind4e1e422019-03-18 16:00:41 -0600561
Alex Klein1699fab2022-09-08 08:46:06 -0600562 def _CreateGomaLogFile(
563 self,
564 goma_log_dir: Union[str, os.PathLike],
565 name: str,
566 timestamp: datetime.datetime,
567 ):
568 """Creates a log file for testing.
Michael Mortensen798ee192020-01-17 13:04:43 -0700569
Alex Klein1699fab2022-09-08 08:46:06 -0600570 Args:
571 goma_log_dir: Directory where the file will be created.
572 name: Log file 'base' name that is combined with the timestamp.
573 timestamp: Timestamp that is written to the file.
574 """
575 path = os.path.join(
576 goma_log_dir,
577 "%s.host.log.INFO.%s"
578 % (name, timestamp.strftime("%Y%m%d-%H%M%S.%f")),
579 )
580 osutils.WriteFile(
581 path,
582 timestamp.strftime("Goma log file created at: %Y/%m/%d %H:%M:%S"),
583 )
Michael Mortensen798ee192020-01-17 13:04:43 -0700584
Alex Klein1699fab2022-09-08 08:46:06 -0600585 def _CreatePortageLogFile(
586 self,
587 log_path: Union[str, os.PathLike],
588 pkg_info: package_info.PackageInfo,
589 timestamp: datetime.datetime,
590 ):
591 """Creates a log file for testing for individual packages built by Portage.
Lizzy Presland7e23a612021-11-09 21:49:42 +0000592
Alex Klein1699fab2022-09-08 08:46:06 -0600593 Args:
594 log_path: The PORTAGE_LOGDIR path.
595 pkg_info: Package name used to name the log file.
596 timestamp: Timestamp used to name the file.
597 """
598 path = os.path.join(
599 log_path,
600 f"{pkg_info.category}:{pkg_info.pvr}:"
601 f'{timestamp.strftime("%Y%m%d-%H%M%S")}.log',
602 )
603 osutils.WriteFile(
604 path,
605 f"Test log file for package {pkg_info.category}/"
606 f"{pkg_info.package} written to {path}",
607 )
608 return path
Lizzy Presland7e23a612021-11-09 21:49:42 +0000609
Alex Klein1699fab2022-09-08 08:46:06 -0600610 def testValidateOnly(self):
611 """Sanity check that a validate only call does not execute any logic."""
612 patch = self.PatchObject(sysroot_service, "BuildPackages")
Alex Klein231d2da2019-07-22 16:44:45 -0600613
Alex Klein1699fab2022-09-08 08:46:06 -0600614 in_proto = self._InputProto(
615 build_target=self.build_target, sysroot_path=self.sysroot
616 )
617 sysroot_controller.InstallPackages(
618 in_proto, self._OutputProto(), self.validate_only_config
619 )
620 patch.assert_not_called()
Alex Klein231d2da2019-07-22 16:44:45 -0600621
Alex Klein1699fab2022-09-08 08:46:06 -0600622 def testMockCall(self):
623 """Sanity check that a mock call does not execute any logic."""
624 patch = self.PatchObject(sysroot_service, "BuildPackages")
625 request = self._InputProto()
626 response = self._OutputProto()
Alex Klein076841b2019-08-29 15:19:39 -0600627
Alex Klein1699fab2022-09-08 08:46:06 -0600628 rc = sysroot_controller.InstallPackages(
629 request, response, self.mock_call_config
630 )
Alex Klein076841b2019-08-29 15:19:39 -0600631
Alex Klein1699fab2022-09-08 08:46:06 -0600632 patch.assert_not_called()
633 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
Alex Klein076841b2019-08-29 15:19:39 -0600634
Alex Klein1699fab2022-09-08 08:46:06 -0600635 def testMockError(self):
636 """Sanity check that a mock error does not execute any logic."""
637 patch = self.PatchObject(sysroot_service, "BuildPackages")
638 request = self._InputProto()
639 response = self._OutputProto()
Alex Klein076841b2019-08-29 15:19:39 -0600640
Alex Klein1699fab2022-09-08 08:46:06 -0600641 rc = sysroot_controller.InstallPackages(
642 request, response, self.mock_error_config
643 )
Alex Klein076841b2019-08-29 15:19:39 -0600644
Alex Klein1699fab2022-09-08 08:46:06 -0600645 patch.assert_not_called()
646 self.assertEqual(
647 controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc
648 )
649 self.assertTrue(response.failed_package_data)
Alex Klein076841b2019-08-29 15:19:39 -0600650
Alex Klein1699fab2022-09-08 08:46:06 -0600651 def testArgumentValidationAllMissing(self):
652 """Test missing all arguments."""
653 out_proto = self._OutputProto()
654 in_proto = self._InputProto()
655 with self.assertRaises(cros_build_lib.DieSystemExit):
656 sysroot_controller.InstallPackages(
657 in_proto, out_proto, self.api_config
658 )
Alex Kleind4e1e422019-03-18 16:00:41 -0600659
Alex Klein1699fab2022-09-08 08:46:06 -0600660 def testArgumentValidationNoSysroot(self):
661 """Test missing sysroot path."""
662 out_proto = self._OutputProto()
663 in_proto = self._InputProto(build_target=self.build_target)
664 with self.assertRaises(cros_build_lib.DieSystemExit):
665 sysroot_controller.InstallPackages(
666 in_proto, out_proto, self.api_config
667 )
Alex Kleind4e1e422019-03-18 16:00:41 -0600668
Alex Klein1699fab2022-09-08 08:46:06 -0600669 def testArgumentValidationNoBuildTarget(self):
670 """Test missing build target name."""
671 out_proto = self._OutputProto()
672 in_proto = self._InputProto(sysroot_path=self.sysroot)
673 with self.assertRaises(cros_build_lib.DieSystemExit):
674 sysroot_controller.InstallPackages(
675 in_proto, out_proto, self.api_config
676 )
Alex Kleind4e1e422019-03-18 16:00:41 -0600677
Alex Klein1699fab2022-09-08 08:46:06 -0600678 def testArgumentValidationInvalidSysroot(self):
679 """Test sysroot that hasn't had the toolchain installed."""
680 out_proto = self._OutputProto()
681 in_proto = self._InputProto(
682 build_target=self.build_target, sysroot_path=self.sysroot
683 )
684 self.PatchObject(
685 sysroot_lib.Sysroot, "IsToolchainInstalled", return_value=False
686 )
687 with self.assertRaises(cros_build_lib.DieSystemExit):
688 sysroot_controller.InstallPackages(
689 in_proto, out_proto, self.api_config
690 )
Alex Kleind4e1e422019-03-18 16:00:41 -0600691
Alex Klein1699fab2022-09-08 08:46:06 -0600692 def testArgumentValidationInvalidPackage(self):
693 out_proto = self._OutputProto()
694 in_proto = self._InputProto(
695 build_target=self.build_target,
696 sysroot_path=self.sysroot,
697 packages=["package-1.0.0-r2"],
698 )
699 with self.assertRaises(cros_build_lib.DieSystemExit):
700 sysroot_controller.InstallPackages(
701 in_proto, out_proto, self.api_config
702 )
Alex Kleinca572ee2020-09-03 10:47:14 -0600703
Alex Klein1699fab2022-09-08 08:46:06 -0600704 def testSuccessOutputHandling(self):
705 """Test successful call output handling."""
706 # Prevent argument validation error.
707 self.PatchObject(
708 sysroot_lib.Sysroot, "IsToolchainInstalled", return_value=True
709 )
Alex Kleind4e1e422019-03-18 16:00:41 -0600710
Alex Klein1699fab2022-09-08 08:46:06 -0600711 in_proto = self._InputProto(
712 build_target=self.build_target, sysroot_path=self.sysroot
713 )
714 out_proto = self._OutputProto()
715 self.PatchObject(sysroot_service, "BuildPackages")
Alex Kleind4e1e422019-03-18 16:00:41 -0600716
Alex Klein1699fab2022-09-08 08:46:06 -0600717 rc = sysroot_controller.InstallPackages(
718 in_proto, out_proto, self.api_config
719 )
720 self.assertFalse(rc)
721 self.assertFalse(out_proto.failed_package_data)
Alex Kleind4e1e422019-03-18 16:00:41 -0600722
Alex Klein1699fab2022-09-08 08:46:06 -0600723 def testSuccessPackageIndexes(self):
724 """Test successful call with package_indexes."""
725 # Prevent argument validation error.
726 self.PatchObject(
727 sysroot_lib.Sysroot, "IsToolchainInstalled", return_value=True
728 )
729 package_indexes = [
730 common_pb2.PackageIndexInfo(
731 snapshot_sha="SHA",
732 snapshot_number=5,
733 build_target=common_pb2.BuildTarget(name="board"),
734 location="LOCATION",
735 profile=common_pb2.Profile(name="profile"),
736 ),
737 common_pb2.PackageIndexInfo(
738 snapshot_sha="SHA2",
739 snapshot_number=4,
740 build_target=common_pb2.BuildTarget(name="board"),
741 location="LOCATION2",
742 profile=common_pb2.Profile(name="profile"),
743 ),
744 ]
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600745
Alex Klein1699fab2022-09-08 08:46:06 -0600746 in_proto = self._InputProto(
747 build_target=self.build_target,
748 sysroot_path=self.sysroot,
749 package_indexes=package_indexes,
750 )
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600751
Alex Klein1699fab2022-09-08 08:46:06 -0600752 out_proto = self._OutputProto()
753 rc_patch = self.PatchObject(sysroot_service, "BuildPackagesRunConfig")
754 self.PatchObject(sysroot_service, "BuildPackages")
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600755
Alex Klein1699fab2022-09-08 08:46:06 -0600756 rc = sysroot_controller.InstallPackages(
757 in_proto, out_proto, self.api_config
758 )
759 self.assertFalse(rc)
760 rc_patch.assert_called_with(
761 use_any_chrome=False,
762 usepkg=True,
763 install_debug_symbols=True,
764 packages=[],
765 package_indexes=[
766 binpkg.PackageIndexInfo.from_protobuf(x)
767 for x in package_indexes
768 ],
769 use_flags=[],
770 use_goma=False,
771 use_remoteexec=False,
772 incremental_build=False,
773 dryrun=False,
774 backtrack=sysroot_controller.DEFAULT_BACKTRACK,
775 )
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600776
Alex Klein1699fab2022-09-08 08:46:06 -0600777 def testSuccessWithGomaLogs(self):
778 """Test successful call with goma."""
779 self._CreateGomaLogFile(
780 self.goma_dir,
781 "compiler_proxy",
782 datetime.datetime(2018, 9, 21, 12, 0, 0),
783 )
784 self._CreateGomaLogFile(
785 self.goma_dir,
786 "compiler_proxy-subproc",
787 datetime.datetime(2018, 9, 21, 12, 1, 0),
788 )
789 self._CreateGomaLogFile(
790 self.goma_dir, "gomacc", datetime.datetime(2018, 9, 21, 12, 2, 0)
791 )
Michael Mortensen798ee192020-01-17 13:04:43 -0700792
Alex Klein1699fab2022-09-08 08:46:06 -0600793 # Prevent argument validation error.
794 self.PatchObject(
795 sysroot_lib.Sysroot, "IsToolchainInstalled", return_value=True
796 )
Michael Mortensen798ee192020-01-17 13:04:43 -0700797
Alex Klein1699fab2022-09-08 08:46:06 -0600798 in_proto = self._InputProto(
799 build_target=self.build_target,
800 sysroot_path=self.sysroot,
801 goma_dir=self.goma_dir,
802 goma_log_dir=self.goma_out_dir,
803 )
Michael Mortensen798ee192020-01-17 13:04:43 -0700804
Alex Klein1699fab2022-09-08 08:46:06 -0600805 out_proto = self._OutputProto()
806 self.PatchObject(sysroot_service, "BuildPackages")
Michael Mortensen798ee192020-01-17 13:04:43 -0700807
Alex Klein1699fab2022-09-08 08:46:06 -0600808 rc = sysroot_controller.InstallPackages(
809 in_proto, out_proto, self.api_config
810 )
811 self.assertFalse(rc)
812 self.assertFalse(out_proto.failed_package_data)
813 self.assertCountEqual(
814 out_proto.goma_artifacts.log_files,
815 [
816 "compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz",
817 "compiler_proxy.host.log.INFO.20180921-120000.000000.gz",
818 "gomacc.host.log.INFO.20180921-120200.000000.tar.gz",
819 ],
820 )
Michael Mortensen798ee192020-01-17 13:04:43 -0700821
Alex Klein1699fab2022-09-08 08:46:06 -0600822 def testSuccessWithGomaLogsAndStatsCounterzFiles(self):
823 """Test successful call with goma including stats and counterz files."""
824 self._CreateGomaLogFile(
825 self.goma_dir,
826 "compiler_proxy",
827 datetime.datetime(2018, 9, 21, 12, 0, 0),
828 )
829 self._CreateGomaLogFile(
830 self.goma_dir,
831 "compiler_proxy-subproc",
832 datetime.datetime(2018, 9, 21, 12, 1, 0),
833 )
834 self._CreateGomaLogFile(
835 self.goma_dir, "gomacc", datetime.datetime(2018, 9, 21, 12, 2, 0)
836 )
837 # Create stats and counterz files.
838 osutils.WriteFile(
839 os.path.join(self.goma_dir, "stats.binaryproto"),
840 "File: stats.binaryproto",
841 )
842 osutils.WriteFile(
843 os.path.join(self.goma_dir, "counterz.binaryproto"),
844 "File: counterz.binaryproto",
845 )
Michael Mortensen798ee192020-01-17 13:04:43 -0700846
Alex Klein1699fab2022-09-08 08:46:06 -0600847 # Prevent argument validation error.
848 self.PatchObject(
849 sysroot_lib.Sysroot, "IsToolchainInstalled", return_value=True
850 )
Michael Mortensen798ee192020-01-17 13:04:43 -0700851
Alex Klein1699fab2022-09-08 08:46:06 -0600852 in_proto = self._InputProto(
853 build_target=self.build_target,
854 sysroot_path=self.sysroot,
855 goma_dir=self.goma_dir,
856 goma_log_dir=self.goma_out_dir,
857 goma_stats_file="stats.binaryproto",
858 goma_counterz_file="counterz.binaryproto",
859 )
Michael Mortensen798ee192020-01-17 13:04:43 -0700860
Alex Klein1699fab2022-09-08 08:46:06 -0600861 out_proto = self._OutputProto()
862 self.PatchObject(sysroot_service, "BuildPackages")
Michael Mortensen798ee192020-01-17 13:04:43 -0700863
Alex Klein1699fab2022-09-08 08:46:06 -0600864 rc = sysroot_controller.InstallPackages(
865 in_proto, out_proto, self.api_config
866 )
867 self.assertFalse(rc)
868 self.assertFalse(out_proto.failed_package_data)
869 self.assertCountEqual(
870 out_proto.goma_artifacts.log_files,
871 [
872 "compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz",
873 "compiler_proxy.host.log.INFO.20180921-120000.000000.gz",
874 "gomacc.host.log.INFO.20180921-120200.000000.tar.gz",
875 ],
876 )
877 # Verify that the output dir has 5 files -- since there should be 3 log
878 # files, the stats file, and the counterz file.
879 output_files = os.listdir(self.goma_out_dir)
880 self.assertCountEqual(
881 output_files,
882 [
883 "stats.binaryproto",
884 "counterz.binaryproto",
885 "compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz",
886 "compiler_proxy.host.log.INFO.20180921-120000.000000.gz",
887 "gomacc.host.log.INFO.20180921-120200.000000.tar.gz",
888 ],
889 )
890 self.assertEqual(
891 out_proto.goma_artifacts.counterz_file, "counterz.binaryproto"
892 )
893 self.assertEqual(
894 out_proto.goma_artifacts.stats_file, "stats.binaryproto"
895 )
Michael Mortensen798ee192020-01-17 13:04:43 -0700896
Alex Klein1699fab2022-09-08 08:46:06 -0600897 def testFailureMissingGomaStatsCounterzFiles(self):
898 """Test successful call with goma including stats and counterz files."""
899 self._CreateGomaLogFile(
900 self.goma_dir,
901 "compiler_proxy",
902 datetime.datetime(2018, 9, 21, 12, 0, 0),
903 )
904 self._CreateGomaLogFile(
905 self.goma_dir,
906 "compiler_proxy-subproc",
907 datetime.datetime(2018, 9, 21, 12, 1, 0),
908 )
909 self._CreateGomaLogFile(
910 self.goma_dir, "gomacc", datetime.datetime(2018, 9, 21, 12, 2, 0)
911 )
912 # Note that stats and counterz files are not created, but are specified in
913 # the proto below.
Michael Mortensen798ee192020-01-17 13:04:43 -0700914
Alex Klein1699fab2022-09-08 08:46:06 -0600915 # Prevent argument validation error.
916 self.PatchObject(
917 sysroot_lib.Sysroot, "IsToolchainInstalled", return_value=True
918 )
Michael Mortensen798ee192020-01-17 13:04:43 -0700919
Alex Klein1699fab2022-09-08 08:46:06 -0600920 in_proto = self._InputProto(
921 build_target=self.build_target,
922 sysroot_path=self.sysroot,
923 goma_dir=self.goma_dir,
924 goma_log_dir=self.goma_out_dir,
925 goma_stats_file="stats.binaryproto",
926 goma_counterz_file="counterz.binaryproto",
927 )
Michael Mortensen798ee192020-01-17 13:04:43 -0700928
Alex Klein1699fab2022-09-08 08:46:06 -0600929 out_proto = self._OutputProto()
930 self.PatchObject(sysroot_service, "BuildPackages")
Michael Mortensen798ee192020-01-17 13:04:43 -0700931
Alex Klein1699fab2022-09-08 08:46:06 -0600932 rc = sysroot_controller.InstallPackages(
933 in_proto, out_proto, self.api_config
934 )
935 self.assertFalse(rc)
936 self.assertFalse(out_proto.failed_package_data)
937 self.assertCountEqual(
938 out_proto.goma_artifacts.log_files,
939 [
940 "compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz",
941 "compiler_proxy.host.log.INFO.20180921-120000.000000.gz",
942 "gomacc.host.log.INFO.20180921-120200.000000.tar.gz",
943 ],
944 )
945 self.assertFalse(out_proto.goma_artifacts.counterz_file)
946 self.assertFalse(out_proto.goma_artifacts.stats_file)
Michael Mortensen798ee192020-01-17 13:04:43 -0700947
Alex Klein1699fab2022-09-08 08:46:06 -0600948 def testFailureOutputHandling(self):
949 """Test failed package handling."""
950 # Prevent argument validation error.
951 self.PatchObject(
952 sysroot_lib.Sysroot, "IsToolchainInstalled", return_value=True
953 )
Alex Kleind4e1e422019-03-18 16:00:41 -0600954
Alex Klein1699fab2022-09-08 08:46:06 -0600955 in_proto = self._InputProto(
956 build_target=self.build_target, sysroot_path=self.sysroot
957 )
958 out_proto = self._OutputProto()
Alex Kleind4e1e422019-03-18 16:00:41 -0600959
Alex Klein1699fab2022-09-08 08:46:06 -0600960 # Failed package info and expected list for verification.
961 err_pkgs = ["cat/pkg-1.0-r3", "cat2/pkg2-1.0-r1"]
962 err_cpvs = [package_info.parse(cpv) for cpv in err_pkgs]
963 expected = [("cat", "pkg"), ("cat2", "pkg2")]
Alex Kleind4e1e422019-03-18 16:00:41 -0600964
Alex Klein1699fab2022-09-08 08:46:06 -0600965 new_logs = {}
966 for i, pkg in enumerate(err_pkgs):
967 self._CreatePortageLogFile(
968 self.portage_dir,
969 err_cpvs[i],
970 datetime.datetime(2021, 6, 9, 13, 37, 0),
971 )
972 new_logs[pkg] = self._CreatePortageLogFile(
973 self.portage_dir,
974 err_cpvs[i],
975 datetime.datetime(2021, 6, 9, 16, 20, 0),
976 )
977 # Force error to be raised with the packages.
978 error = sysroot_lib.PackageInstallError(
979 "Error", cros_build_lib.CompletedProcess(), packages=err_cpvs
980 )
981 self.PatchObject(sysroot_service, "BuildPackages", side_effect=error)
Alex Kleind4e1e422019-03-18 16:00:41 -0600982
Alex Klein1699fab2022-09-08 08:46:06 -0600983 rc = sysroot_controller.InstallPackages(
984 in_proto, out_proto, self.api_config
985 )
986 # This needs to return 2 to indicate the available error response.
987 self.assertEqual(
988 controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc
989 )
990 for data in out_proto.failed_package_data:
991 package = controller_util.deserialize_package_info(data.name)
992 cat_pkg = (data.name.category, data.name.package_name)
993 self.assertIn(cat_pkg, expected)
994 self.assertEqual(data.log_path.path, new_logs[package.cpvr])
Lizzy Presland7e23a612021-11-09 21:49:42 +0000995
Alex Klein1699fab2022-09-08 08:46:06 -0600996 def testNoPackageFailureOutputHandling(self):
997 """Test failure handling without packages to report."""
998 # Prevent argument validation error.
999 self.PatchObject(
1000 sysroot_lib.Sysroot, "IsToolchainInstalled", return_value=True
1001 )
Alex Klein2557b4f2019-07-11 14:34:00 -06001002
Alex Klein1699fab2022-09-08 08:46:06 -06001003 in_proto = self._InputProto(
1004 build_target=self.build_target, sysroot_path=self.sysroot
1005 )
1006 out_proto = self._OutputProto()
Alex Klein2557b4f2019-07-11 14:34:00 -06001007
Alex Klein1699fab2022-09-08 08:46:06 -06001008 # Force error to be raised with no packages.
1009 error = sysroot_lib.PackageInstallError(
1010 "Error", cros_build_lib.CompletedProcess(), packages=[]
1011 )
1012 self.PatchObject(sysroot_service, "BuildPackages", side_effect=error)
Alex Klein2557b4f2019-07-11 14:34:00 -06001013
Alex Klein1699fab2022-09-08 08:46:06 -06001014 rc = sysroot_controller.InstallPackages(
1015 in_proto, out_proto, self.api_config
1016 )
1017 # All we really care about is it's not 0 or 2 (response available), so
1018 # test for that rather than a specific return code.
1019 self.assertTrue(rc)
1020 self.assertNotEqual(
1021 controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc
1022 )