blob: 605e99e53fc62009a04c94254fb112d3b1a29684 [file] [log] [blame]
Alex Kleinda35fcf2019-03-07 16:01:15 -07001# -*- coding: utf-8 -*-
2# Copyright 2019 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Sysroot controller tests."""
7
8from __future__ import print_function
9
Michael Mortensen798ee192020-01-17 13:04:43 -070010import datetime
Alex Kleinda35fcf2019-03-07 16:01:15 -070011import os
12
Alex Klein231d2da2019-07-22 16:44:45 -060013from chromite.api import api_config
Alex Klein8cb365a2019-05-15 16:24:53 -060014from chromite.api import controller
Alex Kleinca572ee2020-09-03 10:47:14 -060015from chromite.api.controller import controller_util
Alex Kleinda35fcf2019-03-07 16:01:15 -070016from chromite.api.controller import sysroot as sysroot_controller
17from chromite.api.gen.chromite.api import sysroot_pb2
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -070018from chromite.api.gen.chromiumos import common_pb2
LaMont Jonesc0343fa2020-08-12 18:58:31 -060019from chromite.lib import binpkg
Alex Kleinda35fcf2019-03-07 16:01:15 -070020from chromite.lib import cros_build_lib
21from chromite.lib import cros_test_lib
22from chromite.lib import osutils
Alex Kleinda35fcf2019-03-07 16:01:15 -070023from chromite.lib import sysroot_lib
Alex Klein18a60af2020-06-11 12:08:47 -060024from chromite.lib.parser import package_info
Alex Kleinda35fcf2019-03-07 16:01:15 -070025from chromite.service import sysroot as sysroot_service
26
27
Alex Klein231d2da2019-07-22 16:44:45 -060028class CreateTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -070029 """Create function tests."""
30
31 def _InputProto(self, build_target=None, profile=None, replace=False,
LaMont Jonesc0343fa2020-08-12 18:58:31 -060032 current=False, package_indexes=None):
Alex Kleinda35fcf2019-03-07 16:01:15 -070033 """Helper to build and input proto instance."""
34 proto = sysroot_pb2.SysrootCreateRequest()
35 if build_target:
36 proto.build_target.name = build_target
37 if profile:
38 proto.profile.name = profile
39 if replace:
40 proto.flags.replace = replace
41 if current:
42 proto.flags.chroot_current = current
LaMont Jonesc0343fa2020-08-12 18:58:31 -060043 if package_indexes:
44 proto.package_indexes.extend(package_indexes)
Alex Kleinda35fcf2019-03-07 16:01:15 -070045
46 return proto
47
48 def _OutputProto(self):
49 """Helper to build output proto instance."""
50 return sysroot_pb2.SysrootCreateResponse()
51
Alex Klein231d2da2019-07-22 16:44:45 -060052 def testValidateOnly(self):
53 """Sanity check that a validate only call does not execute any logic."""
54 patch = self.PatchObject(sysroot_service, 'Create')
55
56 board = 'board'
57 profile = None
58 force = False
59 upgrade_chroot = True
60 in_proto = self._InputProto(build_target=board, profile=profile,
61 replace=force, current=not upgrade_chroot)
62 sysroot_controller.Create(in_proto, self._OutputProto(),
63 self.validate_only_config)
64 patch.assert_not_called()
65
Alex Klein076841b2019-08-29 15:19:39 -060066 def testMockCall(self):
67 """Sanity check that a mock call does not execute any logic."""
68 patch = self.PatchObject(sysroot_service, 'Create')
69 request = self._InputProto()
70 response = self._OutputProto()
71
72 rc = sysroot_controller.Create(request, response, self.mock_call_config)
73
74 patch.assert_not_called()
75 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
76
77 def testMockError(self):
78 """Sanity check that a mock error does not execute any logic."""
79 patch = self.PatchObject(sysroot_service, 'Create')
80 request = self._InputProto()
81 response = self._OutputProto()
82
83 rc = sysroot_controller.Create(request, response, self.mock_error_config)
84
85 patch.assert_not_called()
86 self.assertEqual(controller.RETURN_CODE_UNRECOVERABLE, rc)
87
Alex Kleinda35fcf2019-03-07 16:01:15 -070088 def testArgumentValidation(self):
89 """Test the input argument validation."""
90 # Error when no name provided.
91 in_proto = self._InputProto()
92 out_proto = self._OutputProto()
93 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060094 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -070095
96 # Valid when board passed.
97 result = sysroot_lib.Sysroot('/sysroot/path')
98 patch = self.PatchObject(sysroot_service, 'Create', return_value=result)
99 in_proto = self._InputProto('board')
100 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600101 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700102 patch.assert_called_once()
103
104 def testArgumentHandling(self):
105 """Test the arguments get processed and passed correctly."""
106 sysroot_path = '/sysroot/path'
107
108 sysroot = sysroot_lib.Sysroot(sysroot_path)
109 create_patch = self.PatchObject(sysroot_service, 'Create',
110 return_value=sysroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700111 rc_patch = self.PatchObject(sysroot_service, 'SetupBoardRunConfig')
112
113 # Default values.
114 board = 'board'
115 profile = None
116 force = False
117 upgrade_chroot = True
118 in_proto = self._InputProto(build_target=board, profile=profile,
119 replace=force, current=not upgrade_chroot)
120 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600121 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700122
123 # Default value checks.
LaMont Jonesfeffd1b2020-08-05 18:24:59 -0600124 rc_patch.assert_called_with(force=force, upgrade_chroot=upgrade_chroot,
125 package_indexes=[])
Alex Kleinda35fcf2019-03-07 16:01:15 -0700126 self.assertEqual(board, out_proto.sysroot.build_target.name)
127 self.assertEqual(sysroot_path, out_proto.sysroot.path)
128
129 # Not default values.
130 create_patch.reset_mock()
131 board = 'board'
132 profile = 'profile'
133 force = True
134 upgrade_chroot = False
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600135 package_indexes = [
136 common_pb2.PackageIndexInfo(
137 snapshot_sha='SHA', snapshot_number=5,
138 build_target=common_pb2.BuildTarget(name=board),
139 location='LOCATION', profile=common_pb2.Profile(name=profile)),
140 common_pb2.PackageIndexInfo(
141 snapshot_sha='SHA2', snapshot_number=4,
142 build_target=common_pb2.BuildTarget(name=board),
143 location='LOCATION2', profile=common_pb2.Profile(name=profile))]
144
Alex Kleinda35fcf2019-03-07 16:01:15 -0700145 in_proto = self._InputProto(build_target=board, profile=profile,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600146 replace=force, current=not upgrade_chroot,
147 package_indexes=package_indexes)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700148 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600149 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700150
151 # Not default value checks.
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600152 rc_patch.assert_called_with(
153 force=force, package_indexes=[
154 binpkg.PackageIndexInfo.from_protobuf(x)
155 for x in package_indexes
156 ], upgrade_chroot=upgrade_chroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700157 self.assertEqual(board, out_proto.sysroot.build_target.name)
158 self.assertEqual(sysroot_path, out_proto.sysroot.path)
159
160
Michael Mortensen98592f62019-09-27 13:34:18 -0600161class CreateSimpleChromeSysrootTest(cros_test_lib.MockTempDirTestCase,
162 api_config.ApiConfigMixin):
163 """CreateSimpleChromeSysroot function tests."""
164
165 def _InputProto(self, build_target=None, use_flags=None):
166 """Helper to build and input proto instance."""
167 proto = sysroot_pb2.CreateSimpleChromeSysrootRequest()
168 if build_target:
169 proto.build_target.name = build_target
170 if use_flags:
171 proto.use_flags = use_flags
172 return proto
173
174 def _OutputProto(self):
175 """Helper to build output proto instance."""
176 return sysroot_pb2.CreateSimpleChromeSysrootResponse()
177
178 def testValidateOnly(self):
179 """Sanity check that a validate only call does not execute any logic."""
180 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot')
181
182 board = 'board'
183 in_proto = self._InputProto(build_target=board, use_flags=[])
184 sysroot_controller.CreateSimpleChromeSysroot(in_proto, self._OutputProto(),
185 self.validate_only_config)
186 patch.assert_not_called()
187
Michael Mortensen3232ab32020-01-05 19:14:36 -0700188 def testMockCall(self):
189 """Sanity check that a mock call does not execute any logic."""
190 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot')
191
192 board = 'board'
193 in_proto = self._InputProto(build_target=board, use_flags=[])
194 rc = sysroot_controller.CreateSimpleChromeSysroot(in_proto,
195 self._OutputProto(),
196 self.mock_call_config)
197 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
198 patch.assert_not_called()
199
Michael Mortensen98592f62019-09-27 13:34:18 -0600200 def testArgumentValidation(self):
201 """Test the input argument validation."""
202 # Error when no build target provided.
203 in_proto = self._InputProto()
204 out_proto = self._OutputProto()
205 with self.assertRaises(cros_build_lib.DieSystemExit):
206 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
207 self.api_config)
208
209 # Valid when board is specified.
210 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot',
211 return_value='/path/to/sysroot/tar.bz')
212 in_proto = self._InputProto(build_target='board')
213 out_proto = self._OutputProto()
214 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
215 self.api_config)
216 patch.assert_called_once()
217
218
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700219class GenerateArchiveTest(cros_test_lib.MockTempDirTestCase,
220 api_config.ApiConfigMixin):
221 """GenerateArchive function tests."""
222
223 def setUp(self):
224 self.chroot_path = '/path/to/chroot'
225 self.board = 'board'
226
227 def _InputProto(self, build_target=None, chroot_path=None, pkg_list=None):
228 """Helper to build and input proto instance."""
229 # pkg_list will be a list of category/package strings such as
230 # ['virtual/target-fuzzers'].
231 if pkg_list:
232 package_list = []
233 for pkg in pkg_list:
234 pkg_string_parts = pkg.split('/')
Alex Klein18a60af2020-06-11 12:08:47 -0600235 package_info_msg = common_pb2.PackageInfo(
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700236 category=pkg_string_parts[0],
237 package_name=pkg_string_parts[1])
Alex Klein18a60af2020-06-11 12:08:47 -0600238 package_list.append(package_info_msg)
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700239 else:
240 package_list = []
241
242 return sysroot_pb2.SysrootGenerateArchiveRequest(
243 build_target={'name': build_target},
244 chroot={'path': chroot_path},
245 packages=package_list)
246
247 def _OutputProto(self):
248 """Helper to build output proto instance."""
249 return sysroot_pb2.SysrootGenerateArchiveResponse()
250
251 def testValidateOnly(self):
252 """Sanity check that a validate only call does not execute any logic."""
253 patch = self.PatchObject(sysroot_service, 'GenerateArchive')
254
255 in_proto = self._InputProto(build_target=self.board,
256 chroot_path=self.chroot_path,
257 pkg_list=['virtual/target-fuzzers'])
258 sysroot_controller.GenerateArchive(in_proto, self._OutputProto(),
259 self.validate_only_config)
260 patch.assert_not_called()
261
262 def testMockCall(self):
263 """Sanity check that a mock call does not execute any logic."""
264 patch = self.PatchObject(sysroot_service, 'GenerateArchive')
265
266 in_proto = self._InputProto(build_target=self.board,
267 chroot_path=self.chroot_path,
268 pkg_list=['virtual/target-fuzzers'])
269 sysroot_controller.GenerateArchive(in_proto,
270 self._OutputProto(),
271 self.mock_call_config)
272 patch.assert_not_called()
273
274 def testArgumentValidation(self):
275 """Test the input argument validation."""
276 # Error when no build target provided.
277 in_proto = self._InputProto()
278 out_proto = self._OutputProto()
279 with self.assertRaises(cros_build_lib.DieSystemExit):
280 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
281
282 # Error when packages is not specified.
283 in_proto = self._InputProto(build_target='board',
284 chroot_path=self.chroot_path)
285 with self.assertRaises(cros_build_lib.DieSystemExit):
286 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
287
288 # Valid when board, chroot path, and package are specified.
289 patch = self.PatchObject(sysroot_service, 'GenerateArchive',
290 return_value='/path/to/sysroot/tar.bz')
291 in_proto = self._InputProto(build_target='board',
292 chroot_path=self.chroot_path,
293 pkg_list=['virtual/target-fuzzers'])
294 out_proto = self._OutputProto()
295 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
296 patch.assert_called_once()
297
298
Alex Klein231d2da2019-07-22 16:44:45 -0600299class InstallToolchainTest(cros_test_lib.MockTempDirTestCase,
300 api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -0700301 """Install toolchain function tests."""
302
303 def setUp(self):
304 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600305 # Avoid running the portageq command.
306 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleinda35fcf2019-03-07 16:01:15 -0700307 self.board = 'board'
308 self.sysroot = os.path.join(self.tempdir, 'board')
309 self.invalid_sysroot = os.path.join(self.tempdir, 'invalid', 'sysroot')
310 osutils.SafeMakedirs(self.sysroot)
311
312 def _InputProto(self, build_target=None, sysroot_path=None,
313 compile_source=False):
Alex Kleind4e1e422019-03-18 16:00:41 -0600314 """Helper to build an input proto instance."""
Alex Kleinda35fcf2019-03-07 16:01:15 -0700315 proto = sysroot_pb2.InstallToolchainRequest()
316 if build_target:
317 proto.sysroot.build_target.name = build_target
318 if sysroot_path:
319 proto.sysroot.path = sysroot_path
320 if compile_source:
321 proto.flags.compile_source = compile_source
322
323 return proto
324
325 def _OutputProto(self):
326 """Helper to build output proto instance."""
327 return sysroot_pb2.InstallToolchainResponse()
328
Alex Klein231d2da2019-07-22 16:44:45 -0600329 def testValidateOnly(self):
330 """Sanity check that a validate only call does not execute any logic."""
331 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
332
333 in_proto = self._InputProto(build_target=self.board,
334 sysroot_path=self.sysroot)
335 sysroot_controller.InstallToolchain(in_proto, self._OutputProto(),
336 self.validate_only_config)
337 patch.assert_not_called()
338
Alex Klein076841b2019-08-29 15:19:39 -0600339 def testMockCall(self):
340 """Sanity check that a mock call 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_call_config)
347
348 patch.assert_not_called()
349 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
350
351 def testMockError(self):
352 """Sanity check that a mock error does not execute any logic."""
353 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
354 request = self._InputProto()
355 response = self._OutputProto()
356
357 rc = sysroot_controller.InstallToolchain(request, response,
358 self.mock_error_config)
359
360 patch.assert_not_called()
361 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
362 self.assertTrue(response.failed_packages)
363
Alex Kleinda35fcf2019-03-07 16:01:15 -0700364 def testArgumentValidation(self):
365 """Test the argument validation."""
366 # Test errors on missing inputs.
367 out_proto = self._OutputProto()
368 # Both missing.
369 in_proto = self._InputProto()
370 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600371 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700372
373 # Sysroot path missing.
374 in_proto = self._InputProto(build_target=self.board)
375 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600376 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700377
378 # Build target name missing.
379 in_proto = self._InputProto(sysroot_path=self.sysroot)
380 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 # Both provided, but invalid sysroot path.
384 in_proto = self._InputProto(build_target=self.board,
385 sysroot_path=self.invalid_sysroot)
386 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600387 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700388
389 def testSuccessOutputHandling(self):
390 """Test the output is processed and recorded correctly."""
391 self.PatchObject(sysroot_service, 'InstallToolchain')
392 out_proto = self._OutputProto()
393 in_proto = self._InputProto(build_target=self.board,
394 sysroot_path=self.sysroot)
395
Alex Klein231d2da2019-07-22 16:44:45 -0600396 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
397 self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700398 self.assertFalse(rc)
399 self.assertFalse(out_proto.failed_packages)
400
401
402 def testErrorOutputHandling(self):
403 """Test the error output is processed and recorded correctly."""
404 out_proto = self._OutputProto()
405 in_proto = self._InputProto(build_target=self.board,
406 sysroot_path=self.sysroot)
407
408 err_pkgs = ['cat/pkg', 'cat2/pkg2']
Alex Klein18a60af2020-06-11 12:08:47 -0600409 err_cpvs = [package_info.SplitCPV(pkg, strict=False) for pkg in err_pkgs]
Alex Kleinda35fcf2019-03-07 16:01:15 -0700410 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
411 err = sysroot_lib.ToolchainInstallError('Error',
412 cros_build_lib.CommandResult(),
413 tc_info=err_cpvs)
414 self.PatchObject(sysroot_service, 'InstallToolchain', side_effect=err)
415
Alex Klein231d2da2019-07-22 16:44:45 -0600416 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
417 self.api_config)
Alex Klein8cb365a2019-05-15 16:24:53 -0600418 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700419 self.assertTrue(out_proto.failed_packages)
420 for package in out_proto.failed_packages:
421 cat_pkg = (package.category, package.package_name)
422 self.assertIn(cat_pkg, expected)
Alex Kleind4e1e422019-03-18 16:00:41 -0600423
424
Alex Klein231d2da2019-07-22 16:44:45 -0600425class InstallPackagesTest(cros_test_lib.MockTempDirTestCase,
426 api_config.ApiConfigMixin):
Alex Kleind4e1e422019-03-18 16:00:41 -0600427 """InstallPackages tests."""
428
429 def setUp(self):
430 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600431 # Avoid running the portageq command.
432 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleind4e1e422019-03-18 16:00:41 -0600433 self.build_target = 'board'
434 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
435 osutils.SafeMakedirs(self.sysroot)
Michael Mortensen798ee192020-01-17 13:04:43 -0700436 # Set up goma directories.
437 self.goma_dir = os.path.join(self.tempdir, 'goma_dir')
438 osutils.SafeMakedirs(self.goma_dir)
439 self.goma_out_dir = os.path.join(self.tempdir, 'goma_out_dir')
440 osutils.SafeMakedirs(self.goma_out_dir)
Michael Mortensen4ccfb082020-01-22 16:24:03 -0700441 os.environ['GLOG_log_dir'] = self.goma_dir
Alex Kleind4e1e422019-03-18 16:00:41 -0600442
443 def _InputProto(self, build_target=None, sysroot_path=None,
Michael Mortensen798ee192020-01-17 13:04:43 -0700444 build_source=False, goma_dir=None, goma_log_dir=None,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600445 goma_stats_file=None, goma_counterz_file=None,
Alex Kleinca572ee2020-09-03 10:47:14 -0600446 package_indexes=None, packages=None):
Alex Kleind4e1e422019-03-18 16:00:41 -0600447 """Helper to build an input proto instance."""
448 instance = sysroot_pb2.InstallPackagesRequest()
449
450 if build_target:
451 instance.sysroot.build_target.name = build_target
452 if sysroot_path:
453 instance.sysroot.path = sysroot_path
454 if build_source:
455 instance.flags.build_source = build_source
Michael Mortensen798ee192020-01-17 13:04:43 -0700456 if goma_dir:
457 instance.goma_config.goma_dir = goma_dir
458 if goma_log_dir:
459 instance.goma_config.log_dir.dir = goma_log_dir
460 if goma_stats_file:
461 instance.goma_config.stats_file = goma_stats_file
462 if goma_counterz_file:
463 instance.goma_config.counterz_file = goma_counterz_file
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600464 if package_indexes:
465 instance.package_indexes.extend(package_indexes)
Alex Kleinca572ee2020-09-03 10:47:14 -0600466 if packages:
467 for pkg in packages:
468 pkg_info = instance.packages.add()
Alex Klein18a60af2020-06-11 12:08:47 -0600469 cpv = package_info.SplitCPV(pkg, strict=False)
Alex Kleinca572ee2020-09-03 10:47:14 -0600470 controller_util.CPVToPackageInfo(cpv, pkg_info)
Alex Kleind4e1e422019-03-18 16:00:41 -0600471 return instance
472
473 def _OutputProto(self):
474 """Helper to build an empty output proto instance."""
475 return sysroot_pb2.InstallPackagesResponse()
476
Michael Mortensen798ee192020-01-17 13:04:43 -0700477 def _CreateGomaLogFile(self, goma_log_dir, name, timestamp):
478 """Creates a log file for testing.
479
480 Args:
481 goma_log_dir (str): Directory where the file will be created.
482 name (str): Log file 'base' name that is combined with the timestamp.
483 timestamp (datetime): timestamp that is written to the file.
484 """
485 path = os.path.join(
486 goma_log_dir,
487 '%s.host.log.INFO.%s' % (name, timestamp.strftime('%Y%m%d-%H%M%S.%f')))
488 osutils.WriteFile(
489 path,
490 timestamp.strftime('Goma log file created at: %Y/%m/%d %H:%M:%S'))
491
Alex Klein231d2da2019-07-22 16:44:45 -0600492 def testValidateOnly(self):
493 """Sanity check that a validate only call does not execute any logic."""
494 patch = self.PatchObject(sysroot_service, 'BuildPackages')
495
496 in_proto = self._InputProto(build_target=self.build_target,
497 sysroot_path=self.sysroot)
498 sysroot_controller.InstallPackages(in_proto, self._OutputProto(),
499 self.validate_only_config)
500 patch.assert_not_called()
501
Alex Klein076841b2019-08-29 15:19:39 -0600502 def testMockCall(self):
503 """Sanity check that a mock call does not execute any logic."""
504 patch = self.PatchObject(sysroot_service, 'BuildPackages')
505 request = self._InputProto()
506 response = self._OutputProto()
507
508 rc = sysroot_controller.InstallPackages(request, response,
509 self.mock_call_config)
510
511 patch.assert_not_called()
512 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
513
514 def testMockError(self):
515 """Sanity check that a mock error does not execute any logic."""
516 patch = self.PatchObject(sysroot_service, 'BuildPackages')
517 request = self._InputProto()
518 response = self._OutputProto()
519
520 rc = sysroot_controller.InstallPackages(request, response,
521 self.mock_error_config)
522
523 patch.assert_not_called()
524 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
525 self.assertTrue(response.failed_packages)
526
Alex Kleind4e1e422019-03-18 16:00:41 -0600527 def testArgumentValidationAllMissing(self):
528 """Test missing all arguments."""
529 out_proto = self._OutputProto()
530 in_proto = self._InputProto()
531 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600532 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600533
534 def testArgumentValidationNoSysroot(self):
535 """Test missing sysroot path."""
536 out_proto = self._OutputProto()
537 in_proto = self._InputProto(build_target=self.build_target)
538 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600539 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600540
541 def testArgumentValidationNoBuildTarget(self):
542 """Test missing build target name."""
543 out_proto = self._OutputProto()
544 in_proto = self._InputProto(sysroot_path=self.sysroot)
545 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600546 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600547
548 def testArgumentValidationInvalidSysroot(self):
549 """Test sysroot that hasn't had the toolchain installed."""
550 out_proto = self._OutputProto()
551 in_proto = self._InputProto(build_target=self.build_target,
552 sysroot_path=self.sysroot)
553 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
554 return_value=False)
555 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600556 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600557
Alex Kleinca572ee2020-09-03 10:47:14 -0600558 def testArgumentValidationInvalidPackage(self):
559 out_proto = self._OutputProto()
560 in_proto = self._InputProto(build_target=self.build_target,
561 sysroot_path=self.sysroot,
562 packages=['package-1.0.0-r2'])
563 with self.assertRaises(cros_build_lib.DieSystemExit):
564 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
565
Alex Kleind4e1e422019-03-18 16:00:41 -0600566 def testSuccessOutputHandling(self):
567 """Test successful call output handling."""
568 # Prevent argument validation error.
569 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
570 return_value=True)
571
572 in_proto = self._InputProto(build_target=self.build_target,
573 sysroot_path=self.sysroot)
574 out_proto = self._OutputProto()
575 self.PatchObject(sysroot_service, 'BuildPackages')
576
Alex Klein231d2da2019-07-22 16:44:45 -0600577 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
578 self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600579 self.assertFalse(rc)
580 self.assertFalse(out_proto.failed_packages)
581
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600582 def testSuccessPackageIndexes(self):
583 """Test successful call with package_indexes."""
584 # Prevent argument validation error.
585 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
586 return_value=True)
587 package_indexes = [
588 common_pb2.PackageIndexInfo(
589 snapshot_sha='SHA', snapshot_number=5,
590 build_target=common_pb2.BuildTarget(name='board'),
591 location='LOCATION', profile=common_pb2.Profile(name='profile')),
592 common_pb2.PackageIndexInfo(
593 snapshot_sha='SHA2', snapshot_number=4,
594 build_target=common_pb2.BuildTarget(name='board'),
595 location='LOCATION2', profile=common_pb2.Profile(name='profile'))]
596
597 in_proto = self._InputProto(build_target=self.build_target,
598 sysroot_path=self.sysroot,
599 package_indexes=package_indexes)
600
601 out_proto = self._OutputProto()
602 rc_patch = self.PatchObject(sysroot_service, 'BuildPackagesRunConfig')
603 self.PatchObject(sysroot_service, 'BuildPackages')
604
605 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
606 self.api_config)
607 self.assertFalse(rc)
Alex Kleineb76da72021-03-19 10:43:09 -0600608 rc_patch.assert_called_with(
609 usepkg=True,
610 install_debug_symbols=True,
611 packages=[],
612 package_indexes=[
613 binpkg.PackageIndexInfo.from_protobuf(x) for x in package_indexes
614 ],
615 use_flags=[],
616 use_goma=False,
617 incremental_build=False,
618 setup_board=False)
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600619
Michael Mortensen798ee192020-01-17 13:04:43 -0700620 def testSuccessWithGomaLogs(self):
621 """Test successful call with goma."""
622 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
623 datetime.datetime(2018, 9, 21, 12, 0, 0))
624 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
625 datetime.datetime(2018, 9, 21, 12, 1, 0))
626 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
627 datetime.datetime(2018, 9, 21, 12, 2, 0))
628
629 # Prevent argument validation error.
630 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
631 return_value=True)
632
633 in_proto = self._InputProto(build_target=self.build_target,
634 sysroot_path=self.sysroot,
635 goma_dir=self.goma_dir,
636 goma_log_dir=self.goma_out_dir)
637
638 out_proto = self._OutputProto()
639 self.PatchObject(sysroot_service, 'BuildPackages')
640
641 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
642 self.api_config)
643 self.assertFalse(rc)
644 self.assertFalse(out_proto.failed_packages)
645 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
646 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
647 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
648 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
649
650 def testSuccessWithGomaLogsAndStatsCounterzFiles(self):
651 """Test successful call with goma including stats and counterz files."""
652 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
653 datetime.datetime(2018, 9, 21, 12, 0, 0))
654 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
655 datetime.datetime(2018, 9, 21, 12, 1, 0))
656 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
657 datetime.datetime(2018, 9, 21, 12, 2, 0))
658 # Create stats and counterz files.
659 osutils.WriteFile(os.path.join(self.goma_dir, 'stats.binaryproto'),
660 'File: stats.binaryproto')
661 osutils.WriteFile(os.path.join(self.goma_dir, 'counterz.binaryproto'),
662 'File: counterz.binaryproto')
663
664 # Prevent argument validation error.
665 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
666 return_value=True)
667
668 in_proto = self._InputProto(build_target=self.build_target,
669 sysroot_path=self.sysroot,
670 goma_dir=self.goma_dir,
671 goma_log_dir=self.goma_out_dir,
672 goma_stats_file='stats.binaryproto',
673 goma_counterz_file='counterz.binaryproto')
674
675 out_proto = self._OutputProto()
676 self.PatchObject(sysroot_service, 'BuildPackages')
677
678 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
679 self.api_config)
680 self.assertFalse(rc)
681 self.assertFalse(out_proto.failed_packages)
682 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
683 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
684 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
685 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
686 # Verify that the output dir has 5 files -- since there should be 3 log
687 # files, the stats file, and the counterz file.
688 output_files = os.listdir(self.goma_out_dir)
689 self.assertCountEqual(output_files, [
690 'stats.binaryproto',
691 'counterz.binaryproto',
692 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
693 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
694 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
Michael Mortensen1c7439c2020-01-24 14:43:19 -0700695 self.assertEqual(out_proto.goma_artifacts.counterz_file,
696 'counterz.binaryproto')
697 self.assertEqual(out_proto.goma_artifacts.stats_file,
698 'stats.binaryproto')
Michael Mortensen798ee192020-01-17 13:04:43 -0700699
700 def testFailureMissingGomaStatsCounterzFiles(self):
701 """Test successful call with goma including stats and counterz files."""
702 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
703 datetime.datetime(2018, 9, 21, 12, 0, 0))
704 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
705 datetime.datetime(2018, 9, 21, 12, 1, 0))
706 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
707 datetime.datetime(2018, 9, 21, 12, 2, 0))
708 # Note that stats and counterz files are not created, but are specified in
709 # the proto below.
710
711 # Prevent argument validation error.
712 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
713 return_value=True)
714
715 in_proto = self._InputProto(build_target=self.build_target,
716 sysroot_path=self.sysroot,
717 goma_dir=self.goma_dir,
718 goma_log_dir=self.goma_out_dir,
719 goma_stats_file='stats.binaryproto',
720 goma_counterz_file='counterz.binaryproto')
721
722 out_proto = self._OutputProto()
723 self.PatchObject(sysroot_service, 'BuildPackages')
724
Michael Mortensen1d6d5b02020-01-22 07:33:50 -0700725 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
726 self.api_config)
727 self.assertFalse(rc)
728 self.assertFalse(out_proto.failed_packages)
729 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
730 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
731 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
732 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
733 self.assertFalse(out_proto.goma_artifacts.counterz_file)
734 self.assertFalse(out_proto.goma_artifacts.stats_file)
Michael Mortensen798ee192020-01-17 13:04:43 -0700735
Alex Kleind4e1e422019-03-18 16:00:41 -0600736 def testFailureOutputHandling(self):
737 """Test failed package handling."""
738 # Prevent argument validation error.
739 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
740 return_value=True)
741
742 in_proto = self._InputProto(build_target=self.build_target,
743 sysroot_path=self.sysroot)
744 out_proto = self._OutputProto()
745
746 # Failed package info and expected list for verification.
747 err_pkgs = ['cat/pkg', 'cat2/pkg2']
Alex Klein18a60af2020-06-11 12:08:47 -0600748 err_cpvs = [package_info.SplitCPV(cpv, strict=False) for cpv in err_pkgs]
Alex Kleind4e1e422019-03-18 16:00:41 -0600749 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
750
751 # Force error to be raised with the packages.
752 error = sysroot_lib.PackageInstallError('Error',
753 cros_build_lib.CommandResult(),
754 packages=err_cpvs)
755 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
756
Alex Klein231d2da2019-07-22 16:44:45 -0600757 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
758 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600759 # This needs to return 2 to indicate the available error response.
760 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleind4e1e422019-03-18 16:00:41 -0600761 for package in out_proto.failed_packages:
762 cat_pkg = (package.category, package.package_name)
763 self.assertIn(cat_pkg, expected)
Alex Klein2557b4f2019-07-11 14:34:00 -0600764
765 def testNoPackageFailureOutputHandling(self):
766 """Test failure handling without packages to report."""
767 # Prevent argument validation error.
768 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
769 return_value=True)
770
771 in_proto = self._InputProto(build_target=self.build_target,
772 sysroot_path=self.sysroot)
773 out_proto = self._OutputProto()
774
775 # Force error to be raised with no packages.
776 error = sysroot_lib.PackageInstallError('Error',
777 cros_build_lib.CommandResult(),
778 packages=[])
779 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
780
Alex Klein231d2da2019-07-22 16:44:45 -0600781 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
782 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600783 # All we really care about is it's not 0 or 2 (response available), so
784 # test for that rather than a specific return code.
785 self.assertTrue(rc)
786 self.assertNotEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE,
787 rc)