blob: 454ce5125d188876897a3b8244fd5af87866bd1e [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 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
23from chromite.lib import portage_util
24from chromite.lib import sysroot_lib
25from chromite.service import sysroot as sysroot_service
26
27
Mike Frysingeref94e4c2020-02-10 23:59:54 -050028assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
29
30
Alex Klein231d2da2019-07-22 16:44:45 -060031class CreateTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -070032 """Create function tests."""
33
34 def _InputProto(self, build_target=None, profile=None, replace=False,
LaMont Jonesc0343fa2020-08-12 18:58:31 -060035 current=False, package_indexes=None):
Alex Kleinda35fcf2019-03-07 16:01:15 -070036 """Helper to build and input proto instance."""
37 proto = sysroot_pb2.SysrootCreateRequest()
38 if build_target:
39 proto.build_target.name = build_target
40 if profile:
41 proto.profile.name = profile
42 if replace:
43 proto.flags.replace = replace
44 if current:
45 proto.flags.chroot_current = current
LaMont Jonesc0343fa2020-08-12 18:58:31 -060046 if package_indexes:
47 proto.package_indexes.extend(package_indexes)
Alex Kleinda35fcf2019-03-07 16:01:15 -070048
49 return proto
50
51 def _OutputProto(self):
52 """Helper to build output proto instance."""
53 return sysroot_pb2.SysrootCreateResponse()
54
Alex Klein231d2da2019-07-22 16:44:45 -060055 def testValidateOnly(self):
56 """Sanity check that a validate only call does not execute any logic."""
57 patch = self.PatchObject(sysroot_service, 'Create')
58
59 board = 'board'
60 profile = None
61 force = False
62 upgrade_chroot = True
63 in_proto = self._InputProto(build_target=board, profile=profile,
64 replace=force, current=not upgrade_chroot)
65 sysroot_controller.Create(in_proto, self._OutputProto(),
66 self.validate_only_config)
67 patch.assert_not_called()
68
Alex Klein076841b2019-08-29 15:19:39 -060069 def testMockCall(self):
70 """Sanity check that a mock call does not execute any logic."""
71 patch = self.PatchObject(sysroot_service, 'Create')
72 request = self._InputProto()
73 response = self._OutputProto()
74
75 rc = sysroot_controller.Create(request, response, self.mock_call_config)
76
77 patch.assert_not_called()
78 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
79
80 def testMockError(self):
81 """Sanity check that a mock error does not execute any logic."""
82 patch = self.PatchObject(sysroot_service, 'Create')
83 request = self._InputProto()
84 response = self._OutputProto()
85
86 rc = sysroot_controller.Create(request, response, self.mock_error_config)
87
88 patch.assert_not_called()
89 self.assertEqual(controller.RETURN_CODE_UNRECOVERABLE, rc)
90
Alex Kleinda35fcf2019-03-07 16:01:15 -070091 def testArgumentValidation(self):
92 """Test the input argument validation."""
93 # Error when no name provided.
94 in_proto = self._InputProto()
95 out_proto = self._OutputProto()
96 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060097 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -070098
99 # Valid when board passed.
100 result = sysroot_lib.Sysroot('/sysroot/path')
101 patch = self.PatchObject(sysroot_service, 'Create', return_value=result)
102 in_proto = self._InputProto('board')
103 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600104 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700105 patch.assert_called_once()
106
107 def testArgumentHandling(self):
108 """Test the arguments get processed and passed correctly."""
109 sysroot_path = '/sysroot/path'
110
111 sysroot = sysroot_lib.Sysroot(sysroot_path)
112 create_patch = self.PatchObject(sysroot_service, 'Create',
113 return_value=sysroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700114 rc_patch = self.PatchObject(sysroot_service, 'SetupBoardRunConfig')
115
116 # Default values.
117 board = 'board'
118 profile = None
119 force = False
120 upgrade_chroot = True
121 in_proto = self._InputProto(build_target=board, profile=profile,
122 replace=force, current=not upgrade_chroot)
123 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600124 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700125
126 # Default value checks.
LaMont Jonesfeffd1b2020-08-05 18:24:59 -0600127 rc_patch.assert_called_with(force=force, upgrade_chroot=upgrade_chroot,
128 package_indexes=[])
Alex Kleinda35fcf2019-03-07 16:01:15 -0700129 self.assertEqual(board, out_proto.sysroot.build_target.name)
130 self.assertEqual(sysroot_path, out_proto.sysroot.path)
131
132 # Not default values.
133 create_patch.reset_mock()
134 board = 'board'
135 profile = 'profile'
136 force = True
137 upgrade_chroot = False
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600138 package_indexes = [
139 common_pb2.PackageIndexInfo(
140 snapshot_sha='SHA', snapshot_number=5,
141 build_target=common_pb2.BuildTarget(name=board),
142 location='LOCATION', profile=common_pb2.Profile(name=profile)),
143 common_pb2.PackageIndexInfo(
144 snapshot_sha='SHA2', snapshot_number=4,
145 build_target=common_pb2.BuildTarget(name=board),
146 location='LOCATION2', profile=common_pb2.Profile(name=profile))]
147
Alex Kleinda35fcf2019-03-07 16:01:15 -0700148 in_proto = self._InputProto(build_target=board, profile=profile,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600149 replace=force, current=not upgrade_chroot,
150 package_indexes=package_indexes)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700151 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600152 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700153
154 # Not default value checks.
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600155 rc_patch.assert_called_with(
156 force=force, package_indexes=[
157 binpkg.PackageIndexInfo.from_protobuf(x)
158 for x in package_indexes
159 ], upgrade_chroot=upgrade_chroot)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700160 self.assertEqual(board, out_proto.sysroot.build_target.name)
161 self.assertEqual(sysroot_path, out_proto.sysroot.path)
162
163
Michael Mortensen98592f62019-09-27 13:34:18 -0600164class CreateSimpleChromeSysrootTest(cros_test_lib.MockTempDirTestCase,
165 api_config.ApiConfigMixin):
166 """CreateSimpleChromeSysroot function tests."""
167
168 def _InputProto(self, build_target=None, use_flags=None):
169 """Helper to build and input proto instance."""
170 proto = sysroot_pb2.CreateSimpleChromeSysrootRequest()
171 if build_target:
172 proto.build_target.name = build_target
173 if use_flags:
174 proto.use_flags = use_flags
175 return proto
176
177 def _OutputProto(self):
178 """Helper to build output proto instance."""
179 return sysroot_pb2.CreateSimpleChromeSysrootResponse()
180
181 def testValidateOnly(self):
182 """Sanity check that a validate only call does not execute any logic."""
183 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot')
184
185 board = 'board'
186 in_proto = self._InputProto(build_target=board, use_flags=[])
187 sysroot_controller.CreateSimpleChromeSysroot(in_proto, self._OutputProto(),
188 self.validate_only_config)
189 patch.assert_not_called()
190
Michael Mortensen3232ab32020-01-05 19:14:36 -0700191 def testMockCall(self):
192 """Sanity check that a mock call does not execute any logic."""
193 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot')
194
195 board = 'board'
196 in_proto = self._InputProto(build_target=board, use_flags=[])
197 rc = sysroot_controller.CreateSimpleChromeSysroot(in_proto,
198 self._OutputProto(),
199 self.mock_call_config)
200 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
201 patch.assert_not_called()
202
Michael Mortensen98592f62019-09-27 13:34:18 -0600203 def testArgumentValidation(self):
204 """Test the input argument validation."""
205 # Error when no build target provided.
206 in_proto = self._InputProto()
207 out_proto = self._OutputProto()
208 with self.assertRaises(cros_build_lib.DieSystemExit):
209 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
210 self.api_config)
211
212 # Valid when board is specified.
213 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot',
214 return_value='/path/to/sysroot/tar.bz')
215 in_proto = self._InputProto(build_target='board')
216 out_proto = self._OutputProto()
217 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
218 self.api_config)
219 patch.assert_called_once()
220
221
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700222class GenerateArchiveTest(cros_test_lib.MockTempDirTestCase,
223 api_config.ApiConfigMixin):
224 """GenerateArchive function tests."""
225
226 def setUp(self):
227 self.chroot_path = '/path/to/chroot'
228 self.board = 'board'
229
230 def _InputProto(self, build_target=None, chroot_path=None, pkg_list=None):
231 """Helper to build and input proto instance."""
232 # pkg_list will be a list of category/package strings such as
233 # ['virtual/target-fuzzers'].
234 if pkg_list:
235 package_list = []
236 for pkg in pkg_list:
237 pkg_string_parts = pkg.split('/')
238 package_info = common_pb2.PackageInfo(
239 category=pkg_string_parts[0],
240 package_name=pkg_string_parts[1])
241 package_list.append(package_info)
242 else:
243 package_list = []
244
245 return sysroot_pb2.SysrootGenerateArchiveRequest(
246 build_target={'name': build_target},
247 chroot={'path': chroot_path},
248 packages=package_list)
249
250 def _OutputProto(self):
251 """Helper to build output proto instance."""
252 return sysroot_pb2.SysrootGenerateArchiveResponse()
253
254 def testValidateOnly(self):
255 """Sanity check that a validate only call does not execute any logic."""
256 patch = self.PatchObject(sysroot_service, 'GenerateArchive')
257
258 in_proto = self._InputProto(build_target=self.board,
259 chroot_path=self.chroot_path,
260 pkg_list=['virtual/target-fuzzers'])
261 sysroot_controller.GenerateArchive(in_proto, self._OutputProto(),
262 self.validate_only_config)
263 patch.assert_not_called()
264
265 def testMockCall(self):
266 """Sanity check that a mock call does not execute any logic."""
267 patch = self.PatchObject(sysroot_service, 'GenerateArchive')
268
269 in_proto = self._InputProto(build_target=self.board,
270 chroot_path=self.chroot_path,
271 pkg_list=['virtual/target-fuzzers'])
272 sysroot_controller.GenerateArchive(in_proto,
273 self._OutputProto(),
274 self.mock_call_config)
275 patch.assert_not_called()
276
277 def testArgumentValidation(self):
278 """Test the input argument validation."""
279 # Error when no build target provided.
280 in_proto = self._InputProto()
281 out_proto = self._OutputProto()
282 with self.assertRaises(cros_build_lib.DieSystemExit):
283 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
284
285 # Error when packages is not specified.
286 in_proto = self._InputProto(build_target='board',
287 chroot_path=self.chroot_path)
288 with self.assertRaises(cros_build_lib.DieSystemExit):
289 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
290
291 # Valid when board, chroot path, and package are specified.
292 patch = self.PatchObject(sysroot_service, 'GenerateArchive',
293 return_value='/path/to/sysroot/tar.bz')
294 in_proto = self._InputProto(build_target='board',
295 chroot_path=self.chroot_path,
296 pkg_list=['virtual/target-fuzzers'])
297 out_proto = self._OutputProto()
298 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
299 patch.assert_called_once()
300
301
Alex Klein231d2da2019-07-22 16:44:45 -0600302class InstallToolchainTest(cros_test_lib.MockTempDirTestCase,
303 api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -0700304 """Install toolchain function tests."""
305
306 def setUp(self):
307 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600308 # Avoid running the portageq command.
309 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleinda35fcf2019-03-07 16:01:15 -0700310 self.board = 'board'
311 self.sysroot = os.path.join(self.tempdir, 'board')
312 self.invalid_sysroot = os.path.join(self.tempdir, 'invalid', 'sysroot')
313 osutils.SafeMakedirs(self.sysroot)
314
315 def _InputProto(self, build_target=None, sysroot_path=None,
316 compile_source=False):
Alex Kleind4e1e422019-03-18 16:00:41 -0600317 """Helper to build an input proto instance."""
Alex Kleinda35fcf2019-03-07 16:01:15 -0700318 proto = sysroot_pb2.InstallToolchainRequest()
319 if build_target:
320 proto.sysroot.build_target.name = build_target
321 if sysroot_path:
322 proto.sysroot.path = sysroot_path
323 if compile_source:
324 proto.flags.compile_source = compile_source
325
326 return proto
327
328 def _OutputProto(self):
329 """Helper to build output proto instance."""
330 return sysroot_pb2.InstallToolchainResponse()
331
Alex Klein231d2da2019-07-22 16:44:45 -0600332 def testValidateOnly(self):
333 """Sanity check that a validate only call does not execute any logic."""
334 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
335
336 in_proto = self._InputProto(build_target=self.board,
337 sysroot_path=self.sysroot)
338 sysroot_controller.InstallToolchain(in_proto, self._OutputProto(),
339 self.validate_only_config)
340 patch.assert_not_called()
341
Alex Klein076841b2019-08-29 15:19:39 -0600342 def testMockCall(self):
343 """Sanity check that a mock call does not execute any logic."""
344 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
345 request = self._InputProto()
346 response = self._OutputProto()
347
348 rc = sysroot_controller.InstallToolchain(request, response,
349 self.mock_call_config)
350
351 patch.assert_not_called()
352 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
353
354 def testMockError(self):
355 """Sanity check that a mock error does not execute any logic."""
356 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
357 request = self._InputProto()
358 response = self._OutputProto()
359
360 rc = sysroot_controller.InstallToolchain(request, response,
361 self.mock_error_config)
362
363 patch.assert_not_called()
364 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
365 self.assertTrue(response.failed_packages)
366
Alex Kleinda35fcf2019-03-07 16:01:15 -0700367 def testArgumentValidation(self):
368 """Test the argument validation."""
369 # Test errors on missing inputs.
370 out_proto = self._OutputProto()
371 # Both missing.
372 in_proto = self._InputProto()
373 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600374 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700375
376 # Sysroot path missing.
377 in_proto = self._InputProto(build_target=self.board)
378 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600379 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700380
381 # Build target name missing.
382 in_proto = self._InputProto(sysroot_path=self.sysroot)
383 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600384 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700385
386 # Both provided, but invalid sysroot path.
387 in_proto = self._InputProto(build_target=self.board,
388 sysroot_path=self.invalid_sysroot)
389 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600390 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700391
392 def testSuccessOutputHandling(self):
393 """Test the output is processed and recorded correctly."""
394 self.PatchObject(sysroot_service, 'InstallToolchain')
395 out_proto = self._OutputProto()
396 in_proto = self._InputProto(build_target=self.board,
397 sysroot_path=self.sysroot)
398
Alex Klein231d2da2019-07-22 16:44:45 -0600399 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
400 self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700401 self.assertFalse(rc)
402 self.assertFalse(out_proto.failed_packages)
403
404
405 def testErrorOutputHandling(self):
406 """Test the error output is processed and recorded correctly."""
407 out_proto = self._OutputProto()
408 in_proto = self._InputProto(build_target=self.board,
409 sysroot_path=self.sysroot)
410
411 err_pkgs = ['cat/pkg', 'cat2/pkg2']
412 err_cpvs = [portage_util.SplitCPV(pkg, strict=False) for pkg in err_pkgs]
413 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
414 err = sysroot_lib.ToolchainInstallError('Error',
415 cros_build_lib.CommandResult(),
416 tc_info=err_cpvs)
417 self.PatchObject(sysroot_service, 'InstallToolchain', side_effect=err)
418
Alex Klein231d2da2019-07-22 16:44:45 -0600419 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
420 self.api_config)
Alex Klein8cb365a2019-05-15 16:24:53 -0600421 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700422 self.assertTrue(out_proto.failed_packages)
423 for package in out_proto.failed_packages:
424 cat_pkg = (package.category, package.package_name)
425 self.assertIn(cat_pkg, expected)
Alex Kleind4e1e422019-03-18 16:00:41 -0600426
427
Alex Klein231d2da2019-07-22 16:44:45 -0600428class InstallPackagesTest(cros_test_lib.MockTempDirTestCase,
429 api_config.ApiConfigMixin):
Alex Kleind4e1e422019-03-18 16:00:41 -0600430 """InstallPackages tests."""
431
432 def setUp(self):
433 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600434 # Avoid running the portageq command.
435 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleind4e1e422019-03-18 16:00:41 -0600436 self.build_target = 'board'
437 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
438 osutils.SafeMakedirs(self.sysroot)
Michael Mortensen798ee192020-01-17 13:04:43 -0700439 # Set up goma directories.
440 self.goma_dir = os.path.join(self.tempdir, 'goma_dir')
441 osutils.SafeMakedirs(self.goma_dir)
442 self.goma_out_dir = os.path.join(self.tempdir, 'goma_out_dir')
443 osutils.SafeMakedirs(self.goma_out_dir)
Michael Mortensen4ccfb082020-01-22 16:24:03 -0700444 os.environ['GLOG_log_dir'] = self.goma_dir
Alex Kleind4e1e422019-03-18 16:00:41 -0600445
446 def _InputProto(self, build_target=None, sysroot_path=None,
Michael Mortensen798ee192020-01-17 13:04:43 -0700447 build_source=False, goma_dir=None, goma_log_dir=None,
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600448 goma_stats_file=None, goma_counterz_file=None,
449 package_indexes=None):
Alex Kleind4e1e422019-03-18 16:00:41 -0600450 """Helper to build an input proto instance."""
451 instance = sysroot_pb2.InstallPackagesRequest()
452
453 if build_target:
454 instance.sysroot.build_target.name = build_target
455 if sysroot_path:
456 instance.sysroot.path = sysroot_path
457 if build_source:
458 instance.flags.build_source = build_source
Michael Mortensen798ee192020-01-17 13:04:43 -0700459 if goma_dir:
460 instance.goma_config.goma_dir = goma_dir
461 if goma_log_dir:
462 instance.goma_config.log_dir.dir = goma_log_dir
463 if goma_stats_file:
464 instance.goma_config.stats_file = goma_stats_file
465 if goma_counterz_file:
466 instance.goma_config.counterz_file = goma_counterz_file
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600467 if package_indexes:
468 instance.package_indexes.extend(package_indexes)
Alex Kleind4e1e422019-03-18 16:00:41 -0600469
470 return instance
471
472 def _OutputProto(self):
473 """Helper to build an empty output proto instance."""
474 return sysroot_pb2.InstallPackagesResponse()
475
Michael Mortensen798ee192020-01-17 13:04:43 -0700476 def _CreateGomaLogFile(self, goma_log_dir, name, timestamp):
477 """Creates a log file for testing.
478
479 Args:
480 goma_log_dir (str): Directory where the file will be created.
481 name (str): Log file 'base' name that is combined with the timestamp.
482 timestamp (datetime): timestamp that is written to the file.
483 """
484 path = os.path.join(
485 goma_log_dir,
486 '%s.host.log.INFO.%s' % (name, timestamp.strftime('%Y%m%d-%H%M%S.%f')))
487 osutils.WriteFile(
488 path,
489 timestamp.strftime('Goma log file created at: %Y/%m/%d %H:%M:%S'))
490
Alex Klein231d2da2019-07-22 16:44:45 -0600491 def testValidateOnly(self):
492 """Sanity check that a validate only call does not execute any logic."""
493 patch = self.PatchObject(sysroot_service, 'BuildPackages')
494
495 in_proto = self._InputProto(build_target=self.build_target,
496 sysroot_path=self.sysroot)
497 sysroot_controller.InstallPackages(in_proto, self._OutputProto(),
498 self.validate_only_config)
499 patch.assert_not_called()
500
Alex Klein076841b2019-08-29 15:19:39 -0600501 def testMockCall(self):
502 """Sanity check that a mock call does not execute any logic."""
503 patch = self.PatchObject(sysroot_service, 'BuildPackages')
504 request = self._InputProto()
505 response = self._OutputProto()
506
507 rc = sysroot_controller.InstallPackages(request, response,
508 self.mock_call_config)
509
510 patch.assert_not_called()
511 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
512
513 def testMockError(self):
514 """Sanity check that a mock error does not execute any logic."""
515 patch = self.PatchObject(sysroot_service, 'BuildPackages')
516 request = self._InputProto()
517 response = self._OutputProto()
518
519 rc = sysroot_controller.InstallPackages(request, response,
520 self.mock_error_config)
521
522 patch.assert_not_called()
523 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
524 self.assertTrue(response.failed_packages)
525
Alex Kleind4e1e422019-03-18 16:00:41 -0600526 def testArgumentValidationAllMissing(self):
527 """Test missing all arguments."""
528 out_proto = self._OutputProto()
529 in_proto = self._InputProto()
530 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600531 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600532
533 def testArgumentValidationNoSysroot(self):
534 """Test missing sysroot path."""
535 out_proto = self._OutputProto()
536 in_proto = self._InputProto(build_target=self.build_target)
537 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600538 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600539
540 def testArgumentValidationNoBuildTarget(self):
541 """Test missing build target name."""
542 out_proto = self._OutputProto()
543 in_proto = self._InputProto(sysroot_path=self.sysroot)
544 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600545 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600546
547 def testArgumentValidationInvalidSysroot(self):
548 """Test sysroot that hasn't had the toolchain installed."""
549 out_proto = self._OutputProto()
550 in_proto = self._InputProto(build_target=self.build_target,
551 sysroot_path=self.sysroot)
552 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
553 return_value=False)
554 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600555 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600556
557 def testSuccessOutputHandling(self):
558 """Test successful call output handling."""
559 # Prevent argument validation error.
560 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
561 return_value=True)
562
563 in_proto = self._InputProto(build_target=self.build_target,
564 sysroot_path=self.sysroot)
565 out_proto = self._OutputProto()
566 self.PatchObject(sysroot_service, 'BuildPackages')
567
Alex Klein231d2da2019-07-22 16:44:45 -0600568 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
569 self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600570 self.assertFalse(rc)
571 self.assertFalse(out_proto.failed_packages)
572
LaMont Jonesc0343fa2020-08-12 18:58:31 -0600573 def testSuccessPackageIndexes(self):
574 """Test successful call with package_indexes."""
575 # Prevent argument validation error.
576 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
577 return_value=True)
578 package_indexes = [
579 common_pb2.PackageIndexInfo(
580 snapshot_sha='SHA', snapshot_number=5,
581 build_target=common_pb2.BuildTarget(name='board'),
582 location='LOCATION', profile=common_pb2.Profile(name='profile')),
583 common_pb2.PackageIndexInfo(
584 snapshot_sha='SHA2', snapshot_number=4,
585 build_target=common_pb2.BuildTarget(name='board'),
586 location='LOCATION2', profile=common_pb2.Profile(name='profile'))]
587
588 in_proto = self._InputProto(build_target=self.build_target,
589 sysroot_path=self.sysroot,
590 package_indexes=package_indexes)
591
592 out_proto = self._OutputProto()
593 rc_patch = self.PatchObject(sysroot_service, 'BuildPackagesRunConfig')
594 self.PatchObject(sysroot_service, 'BuildPackages')
595
596 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
597 self.api_config)
598 self.assertFalse(rc)
599 rc_patch.assert_called_with(usepkg=True, install_debug_symbols=True,
600 packages=[],
601 package_indexes=[
602 binpkg.PackageIndexInfo.from_protobuf(x)
603 for x in package_indexes
604 ], use_flags=[], use_goma=False,
605 incremental_build=False)
606
Michael Mortensen798ee192020-01-17 13:04:43 -0700607 def testSuccessWithGomaLogs(self):
608 """Test successful call with goma."""
609 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
610 datetime.datetime(2018, 9, 21, 12, 0, 0))
611 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
612 datetime.datetime(2018, 9, 21, 12, 1, 0))
613 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
614 datetime.datetime(2018, 9, 21, 12, 2, 0))
615
616 # Prevent argument validation error.
617 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
618 return_value=True)
619
620 in_proto = self._InputProto(build_target=self.build_target,
621 sysroot_path=self.sysroot,
622 goma_dir=self.goma_dir,
623 goma_log_dir=self.goma_out_dir)
624
625 out_proto = self._OutputProto()
626 self.PatchObject(sysroot_service, 'BuildPackages')
627
628 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
629 self.api_config)
630 self.assertFalse(rc)
631 self.assertFalse(out_proto.failed_packages)
632 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
633 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
634 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
635 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
636
637 def testSuccessWithGomaLogsAndStatsCounterzFiles(self):
638 """Test successful call with goma including stats and counterz files."""
639 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
640 datetime.datetime(2018, 9, 21, 12, 0, 0))
641 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
642 datetime.datetime(2018, 9, 21, 12, 1, 0))
643 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
644 datetime.datetime(2018, 9, 21, 12, 2, 0))
645 # Create stats and counterz files.
646 osutils.WriteFile(os.path.join(self.goma_dir, 'stats.binaryproto'),
647 'File: stats.binaryproto')
648 osutils.WriteFile(os.path.join(self.goma_dir, 'counterz.binaryproto'),
649 'File: counterz.binaryproto')
650
651 # Prevent argument validation error.
652 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
653 return_value=True)
654
655 in_proto = self._InputProto(build_target=self.build_target,
656 sysroot_path=self.sysroot,
657 goma_dir=self.goma_dir,
658 goma_log_dir=self.goma_out_dir,
659 goma_stats_file='stats.binaryproto',
660 goma_counterz_file='counterz.binaryproto')
661
662 out_proto = self._OutputProto()
663 self.PatchObject(sysroot_service, 'BuildPackages')
664
665 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
666 self.api_config)
667 self.assertFalse(rc)
668 self.assertFalse(out_proto.failed_packages)
669 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
670 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
671 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
672 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
673 # Verify that the output dir has 5 files -- since there should be 3 log
674 # files, the stats file, and the counterz file.
675 output_files = os.listdir(self.goma_out_dir)
676 self.assertCountEqual(output_files, [
677 'stats.binaryproto',
678 'counterz.binaryproto',
679 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
680 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
681 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
Michael Mortensen1c7439c2020-01-24 14:43:19 -0700682 self.assertEqual(out_proto.goma_artifacts.counterz_file,
683 'counterz.binaryproto')
684 self.assertEqual(out_proto.goma_artifacts.stats_file,
685 'stats.binaryproto')
Michael Mortensen798ee192020-01-17 13:04:43 -0700686
687 def testFailureMissingGomaStatsCounterzFiles(self):
688 """Test successful call with goma including stats and counterz files."""
689 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
690 datetime.datetime(2018, 9, 21, 12, 0, 0))
691 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
692 datetime.datetime(2018, 9, 21, 12, 1, 0))
693 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
694 datetime.datetime(2018, 9, 21, 12, 2, 0))
695 # Note that stats and counterz files are not created, but are specified in
696 # the proto below.
697
698 # Prevent argument validation error.
699 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
700 return_value=True)
701
702 in_proto = self._InputProto(build_target=self.build_target,
703 sysroot_path=self.sysroot,
704 goma_dir=self.goma_dir,
705 goma_log_dir=self.goma_out_dir,
706 goma_stats_file='stats.binaryproto',
707 goma_counterz_file='counterz.binaryproto')
708
709 out_proto = self._OutputProto()
710 self.PatchObject(sysroot_service, 'BuildPackages')
711
Michael Mortensen1d6d5b02020-01-22 07:33:50 -0700712 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
713 self.api_config)
714 self.assertFalse(rc)
715 self.assertFalse(out_proto.failed_packages)
716 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
717 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
718 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
719 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
720 self.assertFalse(out_proto.goma_artifacts.counterz_file)
721 self.assertFalse(out_proto.goma_artifacts.stats_file)
Michael Mortensen798ee192020-01-17 13:04:43 -0700722
Alex Kleind4e1e422019-03-18 16:00:41 -0600723 def testFailureOutputHandling(self):
724 """Test failed package handling."""
725 # Prevent argument validation error.
726 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
727 return_value=True)
728
729 in_proto = self._InputProto(build_target=self.build_target,
730 sysroot_path=self.sysroot)
731 out_proto = self._OutputProto()
732
733 # Failed package info and expected list for verification.
734 err_pkgs = ['cat/pkg', 'cat2/pkg2']
735 err_cpvs = [portage_util.SplitCPV(cpv, strict=False) for cpv in err_pkgs]
736 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
737
738 # Force error to be raised with the packages.
739 error = sysroot_lib.PackageInstallError('Error',
740 cros_build_lib.CommandResult(),
741 packages=err_cpvs)
742 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
743
Alex Klein231d2da2019-07-22 16:44:45 -0600744 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
745 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600746 # This needs to return 2 to indicate the available error response.
747 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleind4e1e422019-03-18 16:00:41 -0600748 for package in out_proto.failed_packages:
749 cat_pkg = (package.category, package.package_name)
750 self.assertIn(cat_pkg, expected)
Alex Klein2557b4f2019-07-11 14:34:00 -0600751
752 def testNoPackageFailureOutputHandling(self):
753 """Test failure handling without packages to report."""
754 # Prevent argument validation error.
755 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
756 return_value=True)
757
758 in_proto = self._InputProto(build_target=self.build_target,
759 sysroot_path=self.sysroot)
760 out_proto = self._OutputProto()
761
762 # Force error to be raised with no packages.
763 error = sysroot_lib.PackageInstallError('Error',
764 cros_build_lib.CommandResult(),
765 packages=[])
766 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
767
Alex Klein231d2da2019-07-22 16:44:45 -0600768 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
769 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600770 # All we really care about is it's not 0 or 2 (response available), so
771 # test for that rather than a specific return code.
772 self.assertTrue(rc)
773 self.assertNotEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE,
774 rc)