blob: 6f2b3fb32561569ad61062bb54f5552609c3d444 [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
Mike Frysingeref94e4c2020-02-10 23:59:54 -050012import sys
Alex Kleinda35fcf2019-03-07 16:01:15 -070013
Alex Klein231d2da2019-07-22 16:44:45 -060014from chromite.api import api_config
Alex Klein8cb365a2019-05-15 16:24:53 -060015from chromite.api import controller
Alex Kleinca572ee2020-09-03 10:47:14 -060016from chromite.api.controller import controller_util
Alex Kleinda35fcf2019-03-07 16:01:15 -070017from chromite.api.controller import sysroot as sysroot_controller
18from chromite.api.gen.chromite.api import sysroot_pb2
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -070019from chromite.api.gen.chromiumos import common_pb2
LaMont Jonesc0343fa2020-08-12 18:58:31 -060020from chromite.lib import binpkg
Alex Kleinda35fcf2019-03-07 16:01:15 -070021from chromite.lib import cros_build_lib
22from chromite.lib import cros_test_lib
23from chromite.lib import osutils
24from chromite.lib import portage_util
25from chromite.lib import sysroot_lib
26from chromite.service import sysroot as sysroot_service
27
28
Mike Frysingeref94e4c2020-02-10 23:59:54 -050029assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
30
31
Alex Klein231d2da2019-07-22 16:44:45 -060032class CreateTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -070033 """Create function tests."""
34
35 def _InputProto(self, build_target=None, profile=None, replace=False,
LaMont Jonesc0343fa2020-08-12 18:58:31 -060036 current=False, package_indexes=None):
Alex Kleinda35fcf2019-03-07 16:01:15 -070037 """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
LaMont Jonesc0343fa2020-08-12 18:58:31 -060047 if package_indexes:
48 proto.package_indexes.extend(package_indexes)
Alex Kleinda35fcf2019-03-07 16:01:15 -070049
50 return proto
51
52 def _OutputProto(self):
53 """Helper to build output proto instance."""
54 return sysroot_pb2.SysrootCreateResponse()
55
Alex Klein231d2da2019-07-22 16:44:45 -060056 def testValidateOnly(self):
57 """Sanity check that a validate only call does not execute any logic."""
58 patch = self.PatchObject(sysroot_service, 'Create')
59
60 board = 'board'
61 profile = None
62 force = False
63 upgrade_chroot = True
64 in_proto = self._InputProto(build_target=board, profile=profile,
65 replace=force, current=not upgrade_chroot)
66 sysroot_controller.Create(in_proto, self._OutputProto(),
67 self.validate_only_config)
68 patch.assert_not_called()
69
Alex Klein076841b2019-08-29 15:19:39 -060070 def testMockCall(self):
71 """Sanity check that a mock call does not execute any logic."""
72 patch = self.PatchObject(sysroot_service, 'Create')
73 request = self._InputProto()
74 response = self._OutputProto()
75
76 rc = sysroot_controller.Create(request, response, self.mock_call_config)
77
78 patch.assert_not_called()
79 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
80
81 def testMockError(self):
82 """Sanity check that a mock error does not execute any logic."""
83 patch = self.PatchObject(sysroot_service, 'Create')
84 request = self._InputProto()
85 response = self._OutputProto()
86
87 rc = sysroot_controller.Create(request, response, self.mock_error_config)
88
89 patch.assert_not_called()
90 self.assertEqual(controller.RETURN_CODE_UNRECOVERABLE, rc)
91
Alex Kleinda35fcf2019-03-07 16:01:15 -070092 def testArgumentValidation(self):
93 """Test the input argument validation."""
94 # Error when no name provided.
95 in_proto = self._InputProto()
96 out_proto = self._OutputProto()
97 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060098 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -070099
100 # Valid when board passed.
101 result = sysroot_lib.Sysroot('/sysroot/path')
102 patch = self.PatchObject(sysroot_service, 'Create', return_value=result)
103 in_proto = self._InputProto('board')
104 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600105 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700106 patch.assert_called_once()
107
108 def testArgumentHandling(self):
109 """Test the arguments get processed and passed correctly."""
110 sysroot_path = '/sysroot/path'
111
112 sysroot = sysroot_lib.Sysroot(sysroot_path)
113 create_patch = self.PatchObject(sysroot_service, 'Create',
114 return_value=sysroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700115 rc_patch = self.PatchObject(sysroot_service, 'SetupBoardRunConfig')
116
117 # Default values.
118 board = 'board'
119 profile = None
120 force = False
121 upgrade_chroot = True
122 in_proto = self._InputProto(build_target=board, profile=profile,
123 replace=force, current=not upgrade_chroot)
124 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600125 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700126
127 # Default value checks.
LaMont Jonesfeffd1b2020-08-05 18:24:59 -0600128 rc_patch.assert_called_with(force=force, upgrade_chroot=upgrade_chroot,
129 package_indexes=[])
Alex Kleinda35fcf2019-03-07 16:01:15 -0700130 self.assertEqual(board, out_proto.sysroot.build_target.name)
131 self.assertEqual(sysroot_path, out_proto.sysroot.path)
132
133 # Not default values.
134 create_patch.reset_mock()
135 board = 'board'
136 profile = 'profile'
137 force = True
138 upgrade_chroot = False
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600139 package_indexes = [
140 common_pb2.PackageIndexInfo(
141 snapshot_sha='SHA', snapshot_number=5,
142 build_target=common_pb2.BuildTarget(name=board),
143 location='LOCATION', profile=common_pb2.Profile(name=profile)),
144 common_pb2.PackageIndexInfo(
145 snapshot_sha='SHA2', snapshot_number=4,
146 build_target=common_pb2.BuildTarget(name=board),
147 location='LOCATION2', profile=common_pb2.Profile(name=profile))]
148
Alex Kleinda35fcf2019-03-07 16:01:15 -0700149 in_proto = self._InputProto(build_target=board, profile=profile,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600150 replace=force, current=not upgrade_chroot,
151 package_indexes=package_indexes)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700152 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600153 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700154
155 # Not default value checks.
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600156 rc_patch.assert_called_with(
157 force=force, package_indexes=[
158 binpkg.PackageIndexInfo.from_protobuf(x)
159 for x in package_indexes
160 ], upgrade_chroot=upgrade_chroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700161 self.assertEqual(board, out_proto.sysroot.build_target.name)
162 self.assertEqual(sysroot_path, out_proto.sysroot.path)
163
164
Michael Mortensen98592f62019-09-27 13:34:18 -0600165class CreateSimpleChromeSysrootTest(cros_test_lib.MockTempDirTestCase,
166 api_config.ApiConfigMixin):
167 """CreateSimpleChromeSysroot function tests."""
168
169 def _InputProto(self, build_target=None, use_flags=None):
170 """Helper to build and input proto instance."""
171 proto = sysroot_pb2.CreateSimpleChromeSysrootRequest()
172 if build_target:
173 proto.build_target.name = build_target
174 if use_flags:
175 proto.use_flags = use_flags
176 return proto
177
178 def _OutputProto(self):
179 """Helper to build output proto instance."""
180 return sysroot_pb2.CreateSimpleChromeSysrootResponse()
181
182 def testValidateOnly(self):
183 """Sanity check that a validate only call does not execute any logic."""
184 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot')
185
186 board = 'board'
187 in_proto = self._InputProto(build_target=board, use_flags=[])
188 sysroot_controller.CreateSimpleChromeSysroot(in_proto, self._OutputProto(),
189 self.validate_only_config)
190 patch.assert_not_called()
191
Michael Mortensen3232ab32020-01-05 19:14:36 -0700192 def testMockCall(self):
193 """Sanity check that a mock call does not execute any logic."""
194 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot')
195
196 board = 'board'
197 in_proto = self._InputProto(build_target=board, use_flags=[])
198 rc = sysroot_controller.CreateSimpleChromeSysroot(in_proto,
199 self._OutputProto(),
200 self.mock_call_config)
201 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
202 patch.assert_not_called()
203
Michael Mortensen98592f62019-09-27 13:34:18 -0600204 def testArgumentValidation(self):
205 """Test the input argument validation."""
206 # Error when no build target provided.
207 in_proto = self._InputProto()
208 out_proto = self._OutputProto()
209 with self.assertRaises(cros_build_lib.DieSystemExit):
210 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
211 self.api_config)
212
213 # Valid when board is specified.
214 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot',
215 return_value='/path/to/sysroot/tar.bz')
216 in_proto = self._InputProto(build_target='board')
217 out_proto = self._OutputProto()
218 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
219 self.api_config)
220 patch.assert_called_once()
221
222
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700223class GenerateArchiveTest(cros_test_lib.MockTempDirTestCase,
224 api_config.ApiConfigMixin):
225 """GenerateArchive function tests."""
226
227 def setUp(self):
228 self.chroot_path = '/path/to/chroot'
229 self.board = 'board'
230
231 def _InputProto(self, build_target=None, chroot_path=None, pkg_list=None):
232 """Helper to build and input proto instance."""
233 # pkg_list will be a list of category/package strings such as
234 # ['virtual/target-fuzzers'].
235 if pkg_list:
236 package_list = []
237 for pkg in pkg_list:
238 pkg_string_parts = pkg.split('/')
239 package_info = common_pb2.PackageInfo(
240 category=pkg_string_parts[0],
241 package_name=pkg_string_parts[1])
242 package_list.append(package_info)
243 else:
244 package_list = []
245
246 return sysroot_pb2.SysrootGenerateArchiveRequest(
247 build_target={'name': build_target},
248 chroot={'path': chroot_path},
249 packages=package_list)
250
251 def _OutputProto(self):
252 """Helper to build output proto instance."""
253 return sysroot_pb2.SysrootGenerateArchiveResponse()
254
255 def testValidateOnly(self):
256 """Sanity check that a validate only call does not execute any logic."""
257 patch = self.PatchObject(sysroot_service, 'GenerateArchive')
258
259 in_proto = self._InputProto(build_target=self.board,
260 chroot_path=self.chroot_path,
261 pkg_list=['virtual/target-fuzzers'])
262 sysroot_controller.GenerateArchive(in_proto, self._OutputProto(),
263 self.validate_only_config)
264 patch.assert_not_called()
265
266 def testMockCall(self):
267 """Sanity check that a mock call does not execute any logic."""
268 patch = self.PatchObject(sysroot_service, 'GenerateArchive')
269
270 in_proto = self._InputProto(build_target=self.board,
271 chroot_path=self.chroot_path,
272 pkg_list=['virtual/target-fuzzers'])
273 sysroot_controller.GenerateArchive(in_proto,
274 self._OutputProto(),
275 self.mock_call_config)
276 patch.assert_not_called()
277
278 def testArgumentValidation(self):
279 """Test the input argument validation."""
280 # Error when no build target provided.
281 in_proto = self._InputProto()
282 out_proto = self._OutputProto()
283 with self.assertRaises(cros_build_lib.DieSystemExit):
284 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
285
286 # Error when packages is not specified.
287 in_proto = self._InputProto(build_target='board',
288 chroot_path=self.chroot_path)
289 with self.assertRaises(cros_build_lib.DieSystemExit):
290 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
291
292 # Valid when board, chroot path, and package are specified.
293 patch = self.PatchObject(sysroot_service, 'GenerateArchive',
294 return_value='/path/to/sysroot/tar.bz')
295 in_proto = self._InputProto(build_target='board',
296 chroot_path=self.chroot_path,
297 pkg_list=['virtual/target-fuzzers'])
298 out_proto = self._OutputProto()
299 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
300 patch.assert_called_once()
301
302
Alex Klein231d2da2019-07-22 16:44:45 -0600303class InstallToolchainTest(cros_test_lib.MockTempDirTestCase,
304 api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -0700305 """Install toolchain function tests."""
306
307 def setUp(self):
308 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600309 # Avoid running the portageq command.
310 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleinda35fcf2019-03-07 16:01:15 -0700311 self.board = 'board'
312 self.sysroot = os.path.join(self.tempdir, 'board')
313 self.invalid_sysroot = os.path.join(self.tempdir, 'invalid', 'sysroot')
314 osutils.SafeMakedirs(self.sysroot)
315
316 def _InputProto(self, build_target=None, sysroot_path=None,
317 compile_source=False):
Alex Kleind4e1e422019-03-18 16:00:41 -0600318 """Helper to build an input proto instance."""
Alex Kleinda35fcf2019-03-07 16:01:15 -0700319 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
326
327 return proto
328
329 def _OutputProto(self):
330 """Helper to build output proto instance."""
331 return sysroot_pb2.InstallToolchainResponse()
332
Alex Klein231d2da2019-07-22 16:44:45 -0600333 def testValidateOnly(self):
334 """Sanity check that a validate only call does not execute any logic."""
335 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
336
337 in_proto = self._InputProto(build_target=self.board,
338 sysroot_path=self.sysroot)
339 sysroot_controller.InstallToolchain(in_proto, self._OutputProto(),
340 self.validate_only_config)
341 patch.assert_not_called()
342
Alex Klein076841b2019-08-29 15:19:39 -0600343 def testMockCall(self):
344 """Sanity check that a mock call does not execute any logic."""
345 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
346 request = self._InputProto()
347 response = self._OutputProto()
348
349 rc = sysroot_controller.InstallToolchain(request, response,
350 self.mock_call_config)
351
352 patch.assert_not_called()
353 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
354
355 def testMockError(self):
356 """Sanity check that a mock error does not execute any logic."""
357 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
358 request = self._InputProto()
359 response = self._OutputProto()
360
361 rc = sysroot_controller.InstallToolchain(request, response,
362 self.mock_error_config)
363
364 patch.assert_not_called()
365 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
366 self.assertTrue(response.failed_packages)
367
Alex Kleinda35fcf2019-03-07 16:01:15 -0700368 def testArgumentValidation(self):
369 """Test the argument validation."""
370 # Test errors on missing inputs.
371 out_proto = self._OutputProto()
372 # Both missing.
373 in_proto = self._InputProto()
374 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600375 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700376
377 # Sysroot path missing.
378 in_proto = self._InputProto(build_target=self.board)
379 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600380 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700381
382 # Build target name missing.
383 in_proto = self._InputProto(sysroot_path=self.sysroot)
384 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600385 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700386
387 # Both provided, but invalid sysroot path.
388 in_proto = self._InputProto(build_target=self.board,
389 sysroot_path=self.invalid_sysroot)
390 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600391 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700392
393 def testSuccessOutputHandling(self):
394 """Test the output is processed and recorded correctly."""
395 self.PatchObject(sysroot_service, 'InstallToolchain')
396 out_proto = self._OutputProto()
397 in_proto = self._InputProto(build_target=self.board,
398 sysroot_path=self.sysroot)
399
Alex Klein231d2da2019-07-22 16:44:45 -0600400 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
401 self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700402 self.assertFalse(rc)
403 self.assertFalse(out_proto.failed_packages)
404
405
406 def testErrorOutputHandling(self):
407 """Test the error output is processed and recorded correctly."""
408 out_proto = self._OutputProto()
409 in_proto = self._InputProto(build_target=self.board,
410 sysroot_path=self.sysroot)
411
412 err_pkgs = ['cat/pkg', 'cat2/pkg2']
413 err_cpvs = [portage_util.SplitCPV(pkg, strict=False) for pkg in err_pkgs]
414 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
415 err = sysroot_lib.ToolchainInstallError('Error',
416 cros_build_lib.CommandResult(),
417 tc_info=err_cpvs)
418 self.PatchObject(sysroot_service, 'InstallToolchain', side_effect=err)
419
Alex Klein231d2da2019-07-22 16:44:45 -0600420 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
421 self.api_config)
Alex Klein8cb365a2019-05-15 16:24:53 -0600422 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700423 self.assertTrue(out_proto.failed_packages)
424 for package in out_proto.failed_packages:
425 cat_pkg = (package.category, package.package_name)
426 self.assertIn(cat_pkg, expected)
Alex Kleind4e1e422019-03-18 16:00:41 -0600427
428
Alex Klein231d2da2019-07-22 16:44:45 -0600429class InstallPackagesTest(cros_test_lib.MockTempDirTestCase,
430 api_config.ApiConfigMixin):
Alex Kleind4e1e422019-03-18 16:00:41 -0600431 """InstallPackages tests."""
432
433 def setUp(self):
434 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600435 # Avoid running the portageq command.
436 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleind4e1e422019-03-18 16:00:41 -0600437 self.build_target = 'board'
438 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
439 osutils.SafeMakedirs(self.sysroot)
Michael Mortensen798ee192020-01-17 13:04:43 -0700440 # Set up goma directories.
441 self.goma_dir = os.path.join(self.tempdir, 'goma_dir')
442 osutils.SafeMakedirs(self.goma_dir)
443 self.goma_out_dir = os.path.join(self.tempdir, 'goma_out_dir')
444 osutils.SafeMakedirs(self.goma_out_dir)
Michael Mortensen4ccfb082020-01-22 16:24:03 -0700445 os.environ['GLOG_log_dir'] = self.goma_dir
Alex Kleind4e1e422019-03-18 16:00:41 -0600446
447 def _InputProto(self, build_target=None, sysroot_path=None,
Michael Mortensen798ee192020-01-17 13:04:43 -0700448 build_source=False, goma_dir=None, goma_log_dir=None,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600449 goma_stats_file=None, goma_counterz_file=None,
Alex Kleinca572ee2020-09-03 10:47:14 -0600450 package_indexes=None, packages=None):
Alex Kleind4e1e422019-03-18 16:00:41 -0600451 """Helper to build an input proto instance."""
452 instance = sysroot_pb2.InstallPackagesRequest()
453
454 if build_target:
455 instance.sysroot.build_target.name = build_target
456 if sysroot_path:
457 instance.sysroot.path = sysroot_path
458 if build_source:
459 instance.flags.build_source = build_source
Michael Mortensen798ee192020-01-17 13:04:43 -0700460 if goma_dir:
461 instance.goma_config.goma_dir = goma_dir
462 if goma_log_dir:
463 instance.goma_config.log_dir.dir = goma_log_dir
464 if goma_stats_file:
465 instance.goma_config.stats_file = goma_stats_file
466 if goma_counterz_file:
467 instance.goma_config.counterz_file = goma_counterz_file
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600468 if package_indexes:
469 instance.package_indexes.extend(package_indexes)
Alex Kleinca572ee2020-09-03 10:47:14 -0600470 if packages:
471 for pkg in packages:
472 pkg_info = instance.packages.add()
473 cpv = portage_util.SplitCPV(pkg, strict=False)
474 controller_util.CPVToPackageInfo(cpv, pkg_info)
Alex Kleind4e1e422019-03-18 16:00:41 -0600475 return instance
476
477 def _OutputProto(self):
478 """Helper to build an empty output proto instance."""
479 return sysroot_pb2.InstallPackagesResponse()
480
Michael Mortensen798ee192020-01-17 13:04:43 -0700481 def _CreateGomaLogFile(self, goma_log_dir, name, timestamp):
482 """Creates a log file for testing.
483
484 Args:
485 goma_log_dir (str): Directory where the file will be created.
486 name (str): Log file 'base' name that is combined with the timestamp.
487 timestamp (datetime): timestamp that is written to the file.
488 """
489 path = os.path.join(
490 goma_log_dir,
491 '%s.host.log.INFO.%s' % (name, timestamp.strftime('%Y%m%d-%H%M%S.%f')))
492 osutils.WriteFile(
493 path,
494 timestamp.strftime('Goma log file created at: %Y/%m/%d %H:%M:%S'))
495
Alex Klein231d2da2019-07-22 16:44:45 -0600496 def testValidateOnly(self):
497 """Sanity check that a validate only call does not execute any logic."""
498 patch = self.PatchObject(sysroot_service, 'BuildPackages')
499
500 in_proto = self._InputProto(build_target=self.build_target,
501 sysroot_path=self.sysroot)
502 sysroot_controller.InstallPackages(in_proto, self._OutputProto(),
503 self.validate_only_config)
504 patch.assert_not_called()
505
Alex Klein076841b2019-08-29 15:19:39 -0600506 def testMockCall(self):
507 """Sanity check that a mock call does not execute any logic."""
508 patch = self.PatchObject(sysroot_service, 'BuildPackages')
509 request = self._InputProto()
510 response = self._OutputProto()
511
512 rc = sysroot_controller.InstallPackages(request, response,
513 self.mock_call_config)
514
515 patch.assert_not_called()
516 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
517
518 def testMockError(self):
519 """Sanity check that a mock error does not execute any logic."""
520 patch = self.PatchObject(sysroot_service, 'BuildPackages')
521 request = self._InputProto()
522 response = self._OutputProto()
523
524 rc = sysroot_controller.InstallPackages(request, response,
525 self.mock_error_config)
526
527 patch.assert_not_called()
528 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
529 self.assertTrue(response.failed_packages)
530
Alex Kleind4e1e422019-03-18 16:00:41 -0600531 def testArgumentValidationAllMissing(self):
532 """Test missing all arguments."""
533 out_proto = self._OutputProto()
534 in_proto = self._InputProto()
535 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600536 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600537
538 def testArgumentValidationNoSysroot(self):
539 """Test missing sysroot path."""
540 out_proto = self._OutputProto()
541 in_proto = self._InputProto(build_target=self.build_target)
542 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600543 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600544
545 def testArgumentValidationNoBuildTarget(self):
546 """Test missing build target name."""
547 out_proto = self._OutputProto()
548 in_proto = self._InputProto(sysroot_path=self.sysroot)
549 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600550 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600551
552 def testArgumentValidationInvalidSysroot(self):
553 """Test sysroot that hasn't had the toolchain installed."""
554 out_proto = self._OutputProto()
555 in_proto = self._InputProto(build_target=self.build_target,
556 sysroot_path=self.sysroot)
557 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
558 return_value=False)
559 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600560 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600561
Alex Kleinca572ee2020-09-03 10:47:14 -0600562 def testArgumentValidationInvalidPackage(self):
563 out_proto = self._OutputProto()
564 in_proto = self._InputProto(build_target=self.build_target,
565 sysroot_path=self.sysroot,
566 packages=['package-1.0.0-r2'])
567 with self.assertRaises(cros_build_lib.DieSystemExit):
568 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
569
Alex Kleind4e1e422019-03-18 16:00:41 -0600570 def testSuccessOutputHandling(self):
571 """Test successful call output handling."""
572 # Prevent argument validation error.
573 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
574 return_value=True)
575
576 in_proto = self._InputProto(build_target=self.build_target,
577 sysroot_path=self.sysroot)
578 out_proto = self._OutputProto()
579 self.PatchObject(sysroot_service, 'BuildPackages')
580
Alex Klein231d2da2019-07-22 16:44:45 -0600581 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
582 self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600583 self.assertFalse(rc)
584 self.assertFalse(out_proto.failed_packages)
585
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600586 def testSuccessPackageIndexes(self):
587 """Test successful call with package_indexes."""
588 # Prevent argument validation error.
589 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
590 return_value=True)
591 package_indexes = [
592 common_pb2.PackageIndexInfo(
593 snapshot_sha='SHA', snapshot_number=5,
594 build_target=common_pb2.BuildTarget(name='board'),
595 location='LOCATION', profile=common_pb2.Profile(name='profile')),
596 common_pb2.PackageIndexInfo(
597 snapshot_sha='SHA2', snapshot_number=4,
598 build_target=common_pb2.BuildTarget(name='board'),
599 location='LOCATION2', profile=common_pb2.Profile(name='profile'))]
600
601 in_proto = self._InputProto(build_target=self.build_target,
602 sysroot_path=self.sysroot,
603 package_indexes=package_indexes)
604
605 out_proto = self._OutputProto()
606 rc_patch = self.PatchObject(sysroot_service, 'BuildPackagesRunConfig')
607 self.PatchObject(sysroot_service, 'BuildPackages')
608
609 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
610 self.api_config)
611 self.assertFalse(rc)
612 rc_patch.assert_called_with(usepkg=True, install_debug_symbols=True,
613 packages=[],
614 package_indexes=[
615 binpkg.PackageIndexInfo.from_protobuf(x)
616 for x in package_indexes
617 ], use_flags=[], use_goma=False,
618 incremental_build=False)
619
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']
748 err_cpvs = [portage_util.SplitCPV(cpv, strict=False) for cpv in err_pkgs]
749 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)