blob: e6e6d0b6bfced9d78d00b2b1ab55b44f8fa432b4 [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(
133 force=force, upgrade_chroot=upgrade_chroot, package_indexes=[])
Alex Kleinda35fcf2019-03-07 16:01:15 -0700134 self.assertEqual(board, out_proto.sysroot.build_target.name)
135 self.assertEqual(sysroot_path, out_proto.sysroot.path)
136
137 # Not default values.
138 create_patch.reset_mock()
139 board = 'board'
140 profile = 'profile'
141 force = True
142 upgrade_chroot = False
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600143 package_indexes = [
144 common_pb2.PackageIndexInfo(
Alex Kleind066b0f2022-07-28 08:47:35 -0600145 snapshot_sha='SHA',
146 snapshot_number=5,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600147 build_target=common_pb2.BuildTarget(name=board),
Alex Kleind066b0f2022-07-28 08:47:35 -0600148 location='LOCATION',
149 profile=common_pb2.Profile(name=profile)),
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600150 common_pb2.PackageIndexInfo(
Alex Kleind066b0f2022-07-28 08:47:35 -0600151 snapshot_sha='SHA2',
152 snapshot_number=4,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600153 build_target=common_pb2.BuildTarget(name=board),
Alex Kleind066b0f2022-07-28 08:47:35 -0600154 location='LOCATION2',
155 profile=common_pb2.Profile(name=profile))
156 ]
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600157
Alex Kleind066b0f2022-07-28 08:47:35 -0600158 in_proto = self._InputProto(
159 build_target=board,
160 profile=profile,
161 replace=force,
162 current=not upgrade_chroot,
163 package_indexes=package_indexes)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700164 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600165 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700166
167 # Not default value checks.
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600168 rc_patch.assert_called_with(
Alex Kleind066b0f2022-07-28 08:47:35 -0600169 force=force,
170 package_indexes=[
171 binpkg.PackageIndexInfo.from_protobuf(x) for x in package_indexes
172 ],
173 upgrade_chroot=upgrade_chroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700174 self.assertEqual(board, out_proto.sysroot.build_target.name)
175 self.assertEqual(sysroot_path, out_proto.sysroot.path)
176
177
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700178class GenerateArchiveTest(cros_test_lib.MockTempDirTestCase,
179 api_config.ApiConfigMixin):
180 """GenerateArchive function tests."""
181
182 def setUp(self):
183 self.chroot_path = '/path/to/chroot'
184 self.board = 'board'
185
186 def _InputProto(self, build_target=None, chroot_path=None, pkg_list=None):
187 """Helper to build and input proto instance."""
188 # pkg_list will be a list of category/package strings such as
189 # ['virtual/target-fuzzers'].
190 if pkg_list:
191 package_list = []
192 for pkg in pkg_list:
193 pkg_string_parts = pkg.split('/')
Alex Klein18a60af2020-06-11 12:08:47 -0600194 package_info_msg = common_pb2.PackageInfo(
Alex Kleind066b0f2022-07-28 08:47:35 -0600195 category=pkg_string_parts[0], package_name=pkg_string_parts[1])
Alex Klein18a60af2020-06-11 12:08:47 -0600196 package_list.append(package_info_msg)
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700197 else:
198 package_list = []
199
200 return sysroot_pb2.SysrootGenerateArchiveRequest(
201 build_target={'name': build_target},
202 chroot={'path': chroot_path},
203 packages=package_list)
204
205 def _OutputProto(self):
206 """Helper to build output proto instance."""
207 return sysroot_pb2.SysrootGenerateArchiveResponse()
208
209 def testValidateOnly(self):
210 """Sanity check that a validate only call does not execute any logic."""
211 patch = self.PatchObject(sysroot_service, 'GenerateArchive')
212
Alex Kleind066b0f2022-07-28 08:47:35 -0600213 in_proto = self._InputProto(
214 build_target=self.board,
215 chroot_path=self.chroot_path,
216 pkg_list=['virtual/target-fuzzers'])
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700217 sysroot_controller.GenerateArchive(in_proto, self._OutputProto(),
218 self.validate_only_config)
219 patch.assert_not_called()
220
221 def testMockCall(self):
222 """Sanity check that a mock call does not execute any logic."""
223 patch = self.PatchObject(sysroot_service, 'GenerateArchive')
224
Alex Kleind066b0f2022-07-28 08:47:35 -0600225 in_proto = self._InputProto(
226 build_target=self.board,
227 chroot_path=self.chroot_path,
228 pkg_list=['virtual/target-fuzzers'])
229 sysroot_controller.GenerateArchive(in_proto, self._OutputProto(),
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700230 self.mock_call_config)
231 patch.assert_not_called()
232
233 def testArgumentValidation(self):
234 """Test the input argument validation."""
235 # Error when no build target provided.
236 in_proto = self._InputProto()
237 out_proto = self._OutputProto()
238 with self.assertRaises(cros_build_lib.DieSystemExit):
239 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
240
241 # Error when packages is not specified.
Alex Kleind066b0f2022-07-28 08:47:35 -0600242 in_proto = self._InputProto(
243 build_target='board', chroot_path=self.chroot_path)
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700244 with self.assertRaises(cros_build_lib.DieSystemExit):
245 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
246
247 # Valid when board, chroot path, and package are specified.
Alex Kleind066b0f2022-07-28 08:47:35 -0600248 patch = self.PatchObject(
249 sysroot_service,
250 'GenerateArchive',
251 return_value='/path/to/sysroot/tar.bz')
252 in_proto = self._InputProto(
253 build_target='board',
254 chroot_path=self.chroot_path,
255 pkg_list=['virtual/target-fuzzers'])
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700256 out_proto = self._OutputProto()
257 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
258 patch.assert_called_once()
259
260
Alex Klein231d2da2019-07-22 16:44:45 -0600261class InstallToolchainTest(cros_test_lib.MockTempDirTestCase,
262 api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -0700263 """Install toolchain function tests."""
264
265 def setUp(self):
266 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600267 # Avoid running the portageq command.
268 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleinda35fcf2019-03-07 16:01:15 -0700269 self.board = 'board'
270 self.sysroot = os.path.join(self.tempdir, 'board')
271 self.invalid_sysroot = os.path.join(self.tempdir, 'invalid', 'sysroot')
272 osutils.SafeMakedirs(self.sysroot)
Lizzy Presland7e23a612021-11-09 21:49:42 +0000273 # Set up portage log directory.
Lizzy Presland4c279832021-11-19 20:27:43 +0000274 self.target_sysroot = sysroot_lib.Sysroot(self.sysroot)
Alex Kleine1c4d4b2022-01-05 14:51:04 -0700275 self.portage_dir = os.path.join(self.tempdir, 'portage_logdir')
276 self.PatchObject(
277 sysroot_lib.Sysroot, 'portage_logdir', new=self.portage_dir)
Lizzy Presland7e23a612021-11-09 21:49:42 +0000278 osutils.SafeMakedirs(self.portage_dir)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700279
Alex Kleind066b0f2022-07-28 08:47:35 -0600280 def _InputProto(self,
281 build_target=None,
282 sysroot_path=None,
Alex Kleinda35fcf2019-03-07 16:01:15 -0700283 compile_source=False):
Alex Kleind4e1e422019-03-18 16:00:41 -0600284 """Helper to build an input proto instance."""
Alex Kleinda35fcf2019-03-07 16:01:15 -0700285 proto = sysroot_pb2.InstallToolchainRequest()
286 if build_target:
287 proto.sysroot.build_target.name = build_target
288 if sysroot_path:
289 proto.sysroot.path = sysroot_path
290 if compile_source:
291 proto.flags.compile_source = compile_source
292
293 return proto
294
295 def _OutputProto(self):
296 """Helper to build output proto instance."""
297 return sysroot_pb2.InstallToolchainResponse()
298
Lizzy Preslandfc1db002022-05-06 18:19:49 +0000299 def _CreatePortageLogFile(self, log_path: Union[str, os.PathLike],
300 pkg_info: package_info.PackageInfo,
301 timestamp: datetime.datetime):
Lizzy Presland7e23a612021-11-09 21:49:42 +0000302 """Creates a log file for testing for individual packages built by Portage.
303
304 Args:
Lizzy Preslandfc1db002022-05-06 18:19:49 +0000305 log_path: The PORTAGE_LOGDIR path.
306 pkg_info: Package name used to name the log file.
307 timestamp: Timestamp used to name the file.
Lizzy Presland7e23a612021-11-09 21:49:42 +0000308 """
Lizzy Presland4c279832021-11-19 20:27:43 +0000309 path = os.path.join(log_path,
Lizzy Presland77741782021-12-13 19:46:42 +0000310 f'{pkg_info.category}:{pkg_info.pvr}:' \
Lizzy Presland7e23a612021-11-09 21:49:42 +0000311 f'{timestamp.strftime("%Y%m%d-%H%M%S")}.log')
Alex Kleind066b0f2022-07-28 08:47:35 -0600312 osutils.WriteFile(
313 path, f'Test log file for package {pkg_info.category}/'
314 f'{pkg_info.package} written to {path}')
Lizzy Presland7e23a612021-11-09 21:49:42 +0000315 return path
316
Alex Klein231d2da2019-07-22 16:44:45 -0600317 def testValidateOnly(self):
318 """Sanity check that a validate only call does not execute any logic."""
319 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
320
Alex Kleind066b0f2022-07-28 08:47:35 -0600321 in_proto = self._InputProto(
322 build_target=self.board, sysroot_path=self.sysroot)
Alex Klein231d2da2019-07-22 16:44:45 -0600323 sysroot_controller.InstallToolchain(in_proto, self._OutputProto(),
324 self.validate_only_config)
325 patch.assert_not_called()
326
Alex Klein076841b2019-08-29 15:19:39 -0600327 def testMockCall(self):
328 """Sanity check that a mock call does not execute any logic."""
329 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
330 request = self._InputProto()
331 response = self._OutputProto()
332
333 rc = sysroot_controller.InstallToolchain(request, response,
334 self.mock_call_config)
335
336 patch.assert_not_called()
337 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
338
339 def testMockError(self):
340 """Sanity check that a mock error does not execute any logic."""
341 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
342 request = self._InputProto()
343 response = self._OutputProto()
344
345 rc = sysroot_controller.InstallToolchain(request, response,
346 self.mock_error_config)
347
348 patch.assert_not_called()
349 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000350 self.assertTrue(response.failed_package_data)
Alex Klein076841b2019-08-29 15:19:39 -0600351
Alex Kleinda35fcf2019-03-07 16:01:15 -0700352 def testArgumentValidation(self):
353 """Test the argument validation."""
354 # Test errors on missing inputs.
355 out_proto = self._OutputProto()
356 # Both missing.
357 in_proto = self._InputProto()
358 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600359 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700360
361 # Sysroot path missing.
362 in_proto = self._InputProto(build_target=self.board)
363 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600364 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700365
366 # Build target name missing.
367 in_proto = self._InputProto(sysroot_path=self.sysroot)
368 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600369 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700370
371 # Both provided, but invalid sysroot path.
Alex Kleind066b0f2022-07-28 08:47:35 -0600372 in_proto = self._InputProto(
373 build_target=self.board, sysroot_path=self.invalid_sysroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700374 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 def testSuccessOutputHandling(self):
378 """Test the output is processed and recorded correctly."""
379 self.PatchObject(sysroot_service, 'InstallToolchain')
380 out_proto = self._OutputProto()
Alex Kleind066b0f2022-07-28 08:47:35 -0600381 in_proto = self._InputProto(
382 build_target=self.board, sysroot_path=self.sysroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700383
Alex Klein231d2da2019-07-22 16:44:45 -0600384 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
385 self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700386 self.assertFalse(rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000387 self.assertFalse(out_proto.failed_package_data)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700388
Alex Kleinda35fcf2019-03-07 16:01:15 -0700389 def testErrorOutputHandling(self):
390 """Test the error output is processed and recorded correctly."""
391 out_proto = self._OutputProto()
Alex Kleind066b0f2022-07-28 08:47:35 -0600392 in_proto = self._InputProto(
393 build_target=self.board, sysroot_path=self.sysroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700394
Lizzy Presland77741782021-12-13 19:46:42 +0000395 err_pkgs = ['cat/pkg-1.0-r1', 'cat2/pkg2-1.0-r1']
Alex Kleinea0c89e2021-09-09 15:17:35 -0600396 err_cpvs = [package_info.parse(pkg) for pkg in err_pkgs]
Alex Kleinda35fcf2019-03-07 16:01:15 -0700397 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
Lizzy Presland7e23a612021-11-09 21:49:42 +0000398
399 new_logs = {}
400 for i, pkg in enumerate(err_pkgs):
Lizzy Presland4c279832021-11-19 20:27:43 +0000401 self._CreatePortageLogFile(self.portage_dir, err_cpvs[i],
Lizzy Presland7e23a612021-11-09 21:49:42 +0000402 datetime.datetime(2021, 6, 9, 13, 37, 0))
Alex Kleind066b0f2022-07-28 08:47:35 -0600403 new_logs[pkg] = self._CreatePortageLogFile(
404 self.portage_dir, err_cpvs[i],
405 datetime.datetime(2021, 6, 9, 16, 20, 0))
Lizzy Presland7e23a612021-11-09 21:49:42 +0000406
Alex Kleind066b0f2022-07-28 08:47:35 -0600407 err = sysroot_lib.ToolchainInstallError(
408 'Error', cros_build_lib.CommandResult(), tc_info=err_cpvs)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700409 self.PatchObject(sysroot_service, 'InstallToolchain', side_effect=err)
410
Alex Klein231d2da2019-07-22 16:44:45 -0600411 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
412 self.api_config)
Alex Klein8cb365a2019-05-15 16:24:53 -0600413 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Lizzy Presland7e23a612021-11-09 21:49:42 +0000414 self.assertTrue(out_proto.failed_package_data)
415 # This needs to return 2 to indicate the available error response.
416 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
417 for data in out_proto.failed_package_data:
418 package = controller_util.deserialize_package_info(data.name)
419 cat_pkg = (data.name.category, data.name.package_name)
420 self.assertIn(cat_pkg, expected)
Lizzy Presland77741782021-12-13 19:46:42 +0000421 self.assertEqual(data.log_path.path, new_logs[package.cpvr])
Lizzy Presland7e23a612021-11-09 21:49:42 +0000422
Alex Kleind4e1e422019-03-18 16:00:41 -0600423
Alex Klein231d2da2019-07-22 16:44:45 -0600424class InstallPackagesTest(cros_test_lib.MockTempDirTestCase,
425 api_config.ApiConfigMixin):
Alex Kleind4e1e422019-03-18 16:00:41 -0600426 """InstallPackages tests."""
427
428 def setUp(self):
429 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600430 # Avoid running the portageq command.
431 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleind4e1e422019-03-18 16:00:41 -0600432 self.build_target = 'board'
433 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
434 osutils.SafeMakedirs(self.sysroot)
Lizzy Presland7e23a612021-11-09 21:49:42 +0000435 # Set up portage log directory.
Lizzy Presland4c279832021-11-19 20:27:43 +0000436 self.target_sysroot = sysroot_lib.Sysroot(self.sysroot)
Alex Kleine1c4d4b2022-01-05 14:51:04 -0700437 self.portage_dir = os.path.join(self.tempdir, 'portage_logdir')
438 self.PatchObject(
439 sysroot_lib.Sysroot, 'portage_logdir', new=self.portage_dir)
Lizzy Presland7e23a612021-11-09 21:49:42 +0000440 osutils.SafeMakedirs(self.portage_dir)
Michael Mortensen798ee192020-01-17 13:04:43 -0700441 # Set up goma directories.
442 self.goma_dir = os.path.join(self.tempdir, 'goma_dir')
443 osutils.SafeMakedirs(self.goma_dir)
444 self.goma_out_dir = os.path.join(self.tempdir, 'goma_out_dir')
445 osutils.SafeMakedirs(self.goma_out_dir)
Michael Mortensen4ccfb082020-01-22 16:24:03 -0700446 os.environ['GLOG_log_dir'] = self.goma_dir
Alex Kleind4e1e422019-03-18 16:00:41 -0600447
Alex Kleind066b0f2022-07-28 08:47:35 -0600448 def _InputProto(self,
449 build_target=None,
450 sysroot_path=None,
451 build_source=False,
452 goma_dir=None,
453 goma_log_dir=None,
454 goma_stats_file=None,
455 goma_counterz_file=None,
456 package_indexes=None,
457 packages=None):
Alex Kleind4e1e422019-03-18 16:00:41 -0600458 """Helper to build an input proto instance."""
459 instance = sysroot_pb2.InstallPackagesRequest()
460
461 if build_target:
462 instance.sysroot.build_target.name = build_target
463 if sysroot_path:
464 instance.sysroot.path = sysroot_path
465 if build_source:
466 instance.flags.build_source = build_source
Michael Mortensen798ee192020-01-17 13:04:43 -0700467 if goma_dir:
468 instance.goma_config.goma_dir = goma_dir
469 if goma_log_dir:
470 instance.goma_config.log_dir.dir = goma_log_dir
471 if goma_stats_file:
472 instance.goma_config.stats_file = goma_stats_file
473 if goma_counterz_file:
474 instance.goma_config.counterz_file = goma_counterz_file
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600475 if package_indexes:
476 instance.package_indexes.extend(package_indexes)
Alex Kleinca572ee2020-09-03 10:47:14 -0600477 if packages:
478 for pkg in packages:
Alex Kleinb397b792021-09-09 15:55:45 -0600479 pkg_info = package_info.parse(pkg)
480 pkg_info_msg = instance.packages.add()
481 controller_util.serialize_package_info(pkg_info, pkg_info_msg)
Alex Kleind4e1e422019-03-18 16:00:41 -0600482 return instance
483
484 def _OutputProto(self):
485 """Helper to build an empty output proto instance."""
486 return sysroot_pb2.InstallPackagesResponse()
487
Lizzy Preslandfc1db002022-05-06 18:19:49 +0000488 def _CreateGomaLogFile(self, goma_log_dir: Union[str, os.PathLike], name: str,
489 timestamp: datetime.datetime):
Michael Mortensen798ee192020-01-17 13:04:43 -0700490 """Creates a log file for testing.
491
492 Args:
Lizzy Preslandfc1db002022-05-06 18:19:49 +0000493 goma_log_dir: Directory where the file will be created.
494 name: Log file 'base' name that is combined with the timestamp.
495 timestamp: Timestamp that is written to the file.
Michael Mortensen798ee192020-01-17 13:04:43 -0700496 """
497 path = os.path.join(
498 goma_log_dir,
499 '%s.host.log.INFO.%s' % (name, timestamp.strftime('%Y%m%d-%H%M%S.%f')))
500 osutils.WriteFile(
Alex Kleind066b0f2022-07-28 08:47:35 -0600501 path, timestamp.strftime('Goma log file created at: %Y/%m/%d %H:%M:%S'))
Michael Mortensen798ee192020-01-17 13:04:43 -0700502
Lizzy Preslandfc1db002022-05-06 18:19:49 +0000503 def _CreatePortageLogFile(self, log_path: Union[str, os.PathLike],
504 pkg_info: package_info.PackageInfo,
505 timestamp: datetime.datetime):
Lizzy Presland7e23a612021-11-09 21:49:42 +0000506 """Creates a log file for testing for individual packages built by Portage.
507
508 Args:
Lizzy Preslandfc1db002022-05-06 18:19:49 +0000509 log_path: The PORTAGE_LOGDIR path.
510 pkg_info: Package name used to name the log file.
511 timestamp: Timestamp used to name the file.
Lizzy Presland7e23a612021-11-09 21:49:42 +0000512 """
Lizzy Presland4c279832021-11-19 20:27:43 +0000513 path = os.path.join(log_path,
Lizzy Presland77741782021-12-13 19:46:42 +0000514 f'{pkg_info.category}:{pkg_info.pvr}:' \
Lizzy Presland7e23a612021-11-09 21:49:42 +0000515 f'{timestamp.strftime("%Y%m%d-%H%M%S")}.log')
Alex Kleind066b0f2022-07-28 08:47:35 -0600516 osutils.WriteFile(
517 path, f'Test log file for package {pkg_info.category}/'
518 f'{pkg_info.package} written to {path}')
Lizzy Presland7e23a612021-11-09 21:49:42 +0000519 return path
520
Alex Klein231d2da2019-07-22 16:44:45 -0600521 def testValidateOnly(self):
522 """Sanity check that a validate only call does not execute any logic."""
523 patch = self.PatchObject(sysroot_service, 'BuildPackages')
524
Alex Kleind066b0f2022-07-28 08:47:35 -0600525 in_proto = self._InputProto(
526 build_target=self.build_target, sysroot_path=self.sysroot)
Alex Klein231d2da2019-07-22 16:44:45 -0600527 sysroot_controller.InstallPackages(in_proto, self._OutputProto(),
528 self.validate_only_config)
529 patch.assert_not_called()
530
Alex Klein076841b2019-08-29 15:19:39 -0600531 def testMockCall(self):
532 """Sanity check that a mock call does not execute any logic."""
533 patch = self.PatchObject(sysroot_service, 'BuildPackages')
534 request = self._InputProto()
535 response = self._OutputProto()
536
537 rc = sysroot_controller.InstallPackages(request, response,
538 self.mock_call_config)
539
540 patch.assert_not_called()
541 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
542
543 def testMockError(self):
544 """Sanity check that a mock error does not execute any logic."""
545 patch = self.PatchObject(sysroot_service, 'BuildPackages')
546 request = self._InputProto()
547 response = self._OutputProto()
548
549 rc = sysroot_controller.InstallPackages(request, response,
550 self.mock_error_config)
551
552 patch.assert_not_called()
553 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000554 self.assertTrue(response.failed_package_data)
Alex Klein076841b2019-08-29 15:19:39 -0600555
Alex Kleind4e1e422019-03-18 16:00:41 -0600556 def testArgumentValidationAllMissing(self):
557 """Test missing all arguments."""
558 out_proto = self._OutputProto()
559 in_proto = self._InputProto()
560 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600561 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600562
563 def testArgumentValidationNoSysroot(self):
564 """Test missing sysroot path."""
565 out_proto = self._OutputProto()
566 in_proto = self._InputProto(build_target=self.build_target)
567 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600568 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600569
570 def testArgumentValidationNoBuildTarget(self):
571 """Test missing build target name."""
572 out_proto = self._OutputProto()
573 in_proto = self._InputProto(sysroot_path=self.sysroot)
574 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600575 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600576
577 def testArgumentValidationInvalidSysroot(self):
578 """Test sysroot that hasn't had the toolchain installed."""
579 out_proto = self._OutputProto()
Alex Kleind066b0f2022-07-28 08:47:35 -0600580 in_proto = self._InputProto(
581 build_target=self.build_target, sysroot_path=self.sysroot)
582 self.PatchObject(
583 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=False)
Alex Kleind4e1e422019-03-18 16:00:41 -0600584 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600585 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600586
Alex Kleinca572ee2020-09-03 10:47:14 -0600587 def testArgumentValidationInvalidPackage(self):
588 out_proto = self._OutputProto()
Alex Kleind066b0f2022-07-28 08:47:35 -0600589 in_proto = self._InputProto(
590 build_target=self.build_target,
591 sysroot_path=self.sysroot,
592 packages=['package-1.0.0-r2'])
Alex Kleinca572ee2020-09-03 10:47:14 -0600593 with self.assertRaises(cros_build_lib.DieSystemExit):
594 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
595
Alex Kleind4e1e422019-03-18 16:00:41 -0600596 def testSuccessOutputHandling(self):
597 """Test successful call output handling."""
598 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600599 self.PatchObject(
600 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
Alex Kleind4e1e422019-03-18 16:00:41 -0600601
Alex Kleind066b0f2022-07-28 08:47:35 -0600602 in_proto = self._InputProto(
603 build_target=self.build_target, sysroot_path=self.sysroot)
Alex Kleind4e1e422019-03-18 16:00:41 -0600604 out_proto = self._OutputProto()
605 self.PatchObject(sysroot_service, 'BuildPackages')
606
Alex Klein231d2da2019-07-22 16:44:45 -0600607 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
608 self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600609 self.assertFalse(rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000610 self.assertFalse(out_proto.failed_package_data)
Alex Kleind4e1e422019-03-18 16:00:41 -0600611
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600612 def testSuccessPackageIndexes(self):
613 """Test successful call with package_indexes."""
614 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600615 self.PatchObject(
616 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600617 package_indexes = [
618 common_pb2.PackageIndexInfo(
Alex Kleind066b0f2022-07-28 08:47:35 -0600619 snapshot_sha='SHA',
620 snapshot_number=5,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600621 build_target=common_pb2.BuildTarget(name='board'),
Alex Kleind066b0f2022-07-28 08:47:35 -0600622 location='LOCATION',
623 profile=common_pb2.Profile(name='profile')),
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600624 common_pb2.PackageIndexInfo(
Alex Kleind066b0f2022-07-28 08:47:35 -0600625 snapshot_sha='SHA2',
626 snapshot_number=4,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600627 build_target=common_pb2.BuildTarget(name='board'),
Alex Kleind066b0f2022-07-28 08:47:35 -0600628 location='LOCATION2',
629 profile=common_pb2.Profile(name='profile'))
630 ]
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600631
Alex Kleind066b0f2022-07-28 08:47:35 -0600632 in_proto = self._InputProto(
633 build_target=self.build_target,
634 sysroot_path=self.sysroot,
635 package_indexes=package_indexes)
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600636
637 out_proto = self._OutputProto()
638 rc_patch = self.PatchObject(sysroot_service, 'BuildPackagesRunConfig')
639 self.PatchObject(sysroot_service, 'BuildPackages')
640
641 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
642 self.api_config)
643 self.assertFalse(rc)
Alex Kleineb76da72021-03-19 10:43:09 -0600644 rc_patch.assert_called_with(
Cindy Lin7487daa2022-02-23 04:14:10 +0000645 use_any_chrome=False,
Alex Kleineb76da72021-03-19 10:43:09 -0600646 usepkg=True,
647 install_debug_symbols=True,
648 packages=[],
649 package_indexes=[
650 binpkg.PackageIndexInfo.from_protobuf(x) for x in package_indexes
651 ],
652 use_flags=[],
653 use_goma=False,
Joanna Wang1ec0c812021-11-17 17:41:27 -0800654 use_remoteexec=False,
Alex Kleineb76da72021-03-19 10:43:09 -0600655 incremental_build=False,
Navil Perez5766d1b2021-05-26 17:38:15 +0000656 dryrun=False)
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600657
Michael Mortensen798ee192020-01-17 13:04:43 -0700658 def testSuccessWithGomaLogs(self):
659 """Test successful call with goma."""
660 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
661 datetime.datetime(2018, 9, 21, 12, 0, 0))
662 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
663 datetime.datetime(2018, 9, 21, 12, 1, 0))
664 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
665 datetime.datetime(2018, 9, 21, 12, 2, 0))
666
667 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600668 self.PatchObject(
669 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
Michael Mortensen798ee192020-01-17 13:04:43 -0700670
Alex Kleind066b0f2022-07-28 08:47:35 -0600671 in_proto = self._InputProto(
672 build_target=self.build_target,
673 sysroot_path=self.sysroot,
674 goma_dir=self.goma_dir,
675 goma_log_dir=self.goma_out_dir)
Michael Mortensen798ee192020-01-17 13:04:43 -0700676
677 out_proto = self._OutputProto()
678 self.PatchObject(sysroot_service, 'BuildPackages')
679
680 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
681 self.api_config)
682 self.assertFalse(rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000683 self.assertFalse(out_proto.failed_package_data)
Michael Mortensen798ee192020-01-17 13:04:43 -0700684 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
685 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
686 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
Alex Kleind066b0f2022-07-28 08:47:35 -0600687 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'
688 ])
Michael Mortensen798ee192020-01-17 13:04:43 -0700689
690 def testSuccessWithGomaLogsAndStatsCounterzFiles(self):
691 """Test successful call with goma including stats and counterz files."""
692 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
693 datetime.datetime(2018, 9, 21, 12, 0, 0))
694 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
695 datetime.datetime(2018, 9, 21, 12, 1, 0))
696 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
697 datetime.datetime(2018, 9, 21, 12, 2, 0))
698 # Create stats and counterz files.
Alex Kleind066b0f2022-07-28 08:47:35 -0600699 osutils.WriteFile(
700 os.path.join(self.goma_dir, 'stats.binaryproto'),
701 'File: stats.binaryproto')
702 osutils.WriteFile(
703 os.path.join(self.goma_dir, 'counterz.binaryproto'),
704 'File: counterz.binaryproto')
Michael Mortensen798ee192020-01-17 13:04:43 -0700705
706 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600707 self.PatchObject(
708 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
Michael Mortensen798ee192020-01-17 13:04:43 -0700709
Alex Kleind066b0f2022-07-28 08:47:35 -0600710 in_proto = self._InputProto(
711 build_target=self.build_target,
712 sysroot_path=self.sysroot,
713 goma_dir=self.goma_dir,
714 goma_log_dir=self.goma_out_dir,
715 goma_stats_file='stats.binaryproto',
716 goma_counterz_file='counterz.binaryproto')
Michael Mortensen798ee192020-01-17 13:04:43 -0700717
718 out_proto = self._OutputProto()
719 self.PatchObject(sysroot_service, 'BuildPackages')
720
721 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
722 self.api_config)
723 self.assertFalse(rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000724 self.assertFalse(out_proto.failed_package_data)
Michael Mortensen798ee192020-01-17 13:04:43 -0700725 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
726 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
727 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
Alex Kleind066b0f2022-07-28 08:47:35 -0600728 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'
729 ])
Michael Mortensen798ee192020-01-17 13:04:43 -0700730 # Verify that the output dir has 5 files -- since there should be 3 log
731 # files, the stats file, and the counterz file.
732 output_files = os.listdir(self.goma_out_dir)
733 self.assertCountEqual(output_files, [
Alex Kleind066b0f2022-07-28 08:47:35 -0600734 'stats.binaryproto', 'counterz.binaryproto',
Michael Mortensen798ee192020-01-17 13:04:43 -0700735 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
736 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
Alex Kleind066b0f2022-07-28 08:47:35 -0600737 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'
738 ])
Michael Mortensen1c7439c2020-01-24 14:43:19 -0700739 self.assertEqual(out_proto.goma_artifacts.counterz_file,
740 'counterz.binaryproto')
Alex Kleind066b0f2022-07-28 08:47:35 -0600741 self.assertEqual(out_proto.goma_artifacts.stats_file, 'stats.binaryproto')
Michael Mortensen798ee192020-01-17 13:04:43 -0700742
743 def testFailureMissingGomaStatsCounterzFiles(self):
744 """Test successful call with goma including stats and counterz files."""
745 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
746 datetime.datetime(2018, 9, 21, 12, 0, 0))
747 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
748 datetime.datetime(2018, 9, 21, 12, 1, 0))
749 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
750 datetime.datetime(2018, 9, 21, 12, 2, 0))
751 # Note that stats and counterz files are not created, but are specified in
752 # the proto below.
753
754 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600755 self.PatchObject(
756 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
Michael Mortensen798ee192020-01-17 13:04:43 -0700757
Alex Kleind066b0f2022-07-28 08:47:35 -0600758 in_proto = self._InputProto(
759 build_target=self.build_target,
760 sysroot_path=self.sysroot,
761 goma_dir=self.goma_dir,
762 goma_log_dir=self.goma_out_dir,
763 goma_stats_file='stats.binaryproto',
764 goma_counterz_file='counterz.binaryproto')
Michael Mortensen798ee192020-01-17 13:04:43 -0700765
766 out_proto = self._OutputProto()
767 self.PatchObject(sysroot_service, 'BuildPackages')
768
Michael Mortensen1d6d5b02020-01-22 07:33:50 -0700769 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
770 self.api_config)
771 self.assertFalse(rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000772 self.assertFalse(out_proto.failed_package_data)
Michael Mortensen1d6d5b02020-01-22 07:33:50 -0700773 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
774 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
775 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
Alex Kleind066b0f2022-07-28 08:47:35 -0600776 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'
777 ])
Michael Mortensen1d6d5b02020-01-22 07:33:50 -0700778 self.assertFalse(out_proto.goma_artifacts.counterz_file)
779 self.assertFalse(out_proto.goma_artifacts.stats_file)
Michael Mortensen798ee192020-01-17 13:04:43 -0700780
Alex Kleind4e1e422019-03-18 16:00:41 -0600781 def testFailureOutputHandling(self):
782 """Test failed package handling."""
783 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600784 self.PatchObject(
785 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
Alex Kleind4e1e422019-03-18 16:00:41 -0600786
Alex Kleind066b0f2022-07-28 08:47:35 -0600787 in_proto = self._InputProto(
788 build_target=self.build_target, sysroot_path=self.sysroot)
Alex Kleind4e1e422019-03-18 16:00:41 -0600789 out_proto = self._OutputProto()
790
791 # Failed package info and expected list for verification.
Lizzy Presland77741782021-12-13 19:46:42 +0000792 err_pkgs = ['cat/pkg-1.0-r3', 'cat2/pkg2-1.0-r1']
Lizzy Presland7e23a612021-11-09 21:49:42 +0000793 err_cpvs = [package_info.parse(cpv) for cpv in err_pkgs]
Alex Kleind4e1e422019-03-18 16:00:41 -0600794 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
795
Lizzy Presland7e23a612021-11-09 21:49:42 +0000796 new_logs = {}
797 for i, pkg in enumerate(err_pkgs):
Lizzy Presland4c279832021-11-19 20:27:43 +0000798 self._CreatePortageLogFile(self.portage_dir, err_cpvs[i],
Lizzy Presland7e23a612021-11-09 21:49:42 +0000799 datetime.datetime(2021, 6, 9, 13, 37, 0))
Alex Kleind066b0f2022-07-28 08:47:35 -0600800 new_logs[pkg] = self._CreatePortageLogFile(
801 self.portage_dir, err_cpvs[i],
802 datetime.datetime(2021, 6, 9, 16, 20, 0))
Alex Kleind4e1e422019-03-18 16:00:41 -0600803 # Force error to be raised with the packages.
Alex Kleind066b0f2022-07-28 08:47:35 -0600804 error = sysroot_lib.PackageInstallError(
805 'Error', cros_build_lib.CommandResult(), packages=err_cpvs)
Alex Kleind4e1e422019-03-18 16:00:41 -0600806 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
807
Alex Klein231d2da2019-07-22 16:44:45 -0600808 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
809 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600810 # This needs to return 2 to indicate the available error response.
811 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Lizzy Presland7e23a612021-11-09 21:49:42 +0000812 for data in out_proto.failed_package_data:
813 package = controller_util.deserialize_package_info(data.name)
814 cat_pkg = (data.name.category, data.name.package_name)
815 self.assertIn(cat_pkg, expected)
Lizzy Presland77741782021-12-13 19:46:42 +0000816 self.assertEqual(data.log_path.path, new_logs[package.cpvr])
Lizzy Presland7e23a612021-11-09 21:49:42 +0000817
Alex Klein2557b4f2019-07-11 14:34:00 -0600818 def testNoPackageFailureOutputHandling(self):
819 """Test failure handling without packages to report."""
820 # Prevent argument validation error.
Alex Kleind066b0f2022-07-28 08:47:35 -0600821 self.PatchObject(
822 sysroot_lib.Sysroot, 'IsToolchainInstalled', return_value=True)
Alex Klein2557b4f2019-07-11 14:34:00 -0600823
Alex Kleind066b0f2022-07-28 08:47:35 -0600824 in_proto = self._InputProto(
825 build_target=self.build_target, sysroot_path=self.sysroot)
Alex Klein2557b4f2019-07-11 14:34:00 -0600826 out_proto = self._OutputProto()
827
828 # Force error to be raised with no packages.
Alex Kleind066b0f2022-07-28 08:47:35 -0600829 error = sysroot_lib.PackageInstallError(
830 'Error', cros_build_lib.CommandResult(), packages=[])
Alex Klein2557b4f2019-07-11 14:34:00 -0600831 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
832
Alex Klein231d2da2019-07-22 16:44:45 -0600833 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
834 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600835 # All we really care about is it's not 0 or 2 (response available), so
836 # test for that rather than a specific return code.
837 self.assertTrue(rc)
838 self.assertNotEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE,
839 rc)