blob: 789f4f80b4488c53d658a9fe108bee5d82f6cc80 [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
Alex Kleinda35fcf2019-03-07 16:01:15 -070019from chromite.lib import build_target_util
20from 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,
35 current=False):
36 """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
46
47 return proto
48
49 def _OutputProto(self):
50 """Helper to build output proto instance."""
51 return sysroot_pb2.SysrootCreateResponse()
52
Alex Klein231d2da2019-07-22 16:44:45 -060053 def testValidateOnly(self):
54 """Sanity check that a validate only call does not execute any logic."""
55 patch = self.PatchObject(sysroot_service, 'Create')
56
57 board = 'board'
58 profile = None
59 force = False
60 upgrade_chroot = True
61 in_proto = self._InputProto(build_target=board, profile=profile,
62 replace=force, current=not upgrade_chroot)
63 sysroot_controller.Create(in_proto, self._OutputProto(),
64 self.validate_only_config)
65 patch.assert_not_called()
66
Alex Klein076841b2019-08-29 15:19:39 -060067 def testMockCall(self):
68 """Sanity check that a mock call does not execute any logic."""
69 patch = self.PatchObject(sysroot_service, 'Create')
70 request = self._InputProto()
71 response = self._OutputProto()
72
73 rc = sysroot_controller.Create(request, response, self.mock_call_config)
74
75 patch.assert_not_called()
76 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
77
78 def testMockError(self):
79 """Sanity check that a mock error does not execute any logic."""
80 patch = self.PatchObject(sysroot_service, 'Create')
81 request = self._InputProto()
82 response = self._OutputProto()
83
84 rc = sysroot_controller.Create(request, response, self.mock_error_config)
85
86 patch.assert_not_called()
87 self.assertEqual(controller.RETURN_CODE_UNRECOVERABLE, rc)
88
Alex Kleinda35fcf2019-03-07 16:01:15 -070089 def testArgumentValidation(self):
90 """Test the input argument validation."""
91 # Error when no name provided.
92 in_proto = self._InputProto()
93 out_proto = self._OutputProto()
94 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060095 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -070096
97 # Valid when board passed.
98 result = sysroot_lib.Sysroot('/sysroot/path')
99 patch = self.PatchObject(sysroot_service, 'Create', return_value=result)
100 in_proto = self._InputProto('board')
101 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600102 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700103 patch.assert_called_once()
104
105 def testArgumentHandling(self):
106 """Test the arguments get processed and passed correctly."""
107 sysroot_path = '/sysroot/path'
108
109 sysroot = sysroot_lib.Sysroot(sysroot_path)
110 create_patch = self.PatchObject(sysroot_service, 'Create',
111 return_value=sysroot)
112 target_patch = self.PatchObject(build_target_util, 'BuildTarget')
113 rc_patch = self.PatchObject(sysroot_service, 'SetupBoardRunConfig')
114
115 # Default values.
116 board = 'board'
117 profile = None
118 force = False
119 upgrade_chroot = True
120 in_proto = self._InputProto(build_target=board, profile=profile,
121 replace=force, current=not upgrade_chroot)
122 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600123 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700124
125 # Default value checks.
126 target_patch.assert_called_with(name=board, profile=profile)
127 rc_patch.assert_called_with(force=force, upgrade_chroot=upgrade_chroot)
128 self.assertEqual(board, out_proto.sysroot.build_target.name)
129 self.assertEqual(sysroot_path, out_proto.sysroot.path)
130
131 # Not default values.
132 create_patch.reset_mock()
133 board = 'board'
134 profile = 'profile'
135 force = True
136 upgrade_chroot = False
137 in_proto = self._InputProto(build_target=board, profile=profile,
138 replace=force, current=not upgrade_chroot)
139 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600140 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700141
142 # Not default value checks.
143 target_patch.assert_called_with(name=board, profile=profile)
144 rc_patch.assert_called_with(force=force, upgrade_chroot=upgrade_chroot)
145 self.assertEqual(board, out_proto.sysroot.build_target.name)
146 self.assertEqual(sysroot_path, out_proto.sysroot.path)
147
148
Michael Mortensen98592f62019-09-27 13:34:18 -0600149class CreateSimpleChromeSysrootTest(cros_test_lib.MockTempDirTestCase,
150 api_config.ApiConfigMixin):
151 """CreateSimpleChromeSysroot function tests."""
152
153 def _InputProto(self, build_target=None, use_flags=None):
154 """Helper to build and input proto instance."""
155 proto = sysroot_pb2.CreateSimpleChromeSysrootRequest()
156 if build_target:
157 proto.build_target.name = build_target
158 if use_flags:
159 proto.use_flags = use_flags
160 return proto
161
162 def _OutputProto(self):
163 """Helper to build output proto instance."""
164 return sysroot_pb2.CreateSimpleChromeSysrootResponse()
165
166 def testValidateOnly(self):
167 """Sanity check that a validate only call does not execute any logic."""
168 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot')
169
170 board = 'board'
171 in_proto = self._InputProto(build_target=board, use_flags=[])
172 sysroot_controller.CreateSimpleChromeSysroot(in_proto, self._OutputProto(),
173 self.validate_only_config)
174 patch.assert_not_called()
175
Michael Mortensen3232ab32020-01-05 19:14:36 -0700176 def testMockCall(self):
177 """Sanity check that a mock call does not execute any logic."""
178 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot')
179
180 board = 'board'
181 in_proto = self._InputProto(build_target=board, use_flags=[])
182 rc = sysroot_controller.CreateSimpleChromeSysroot(in_proto,
183 self._OutputProto(),
184 self.mock_call_config)
185 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
186 patch.assert_not_called()
187
Michael Mortensen98592f62019-09-27 13:34:18 -0600188 def testArgumentValidation(self):
189 """Test the input argument validation."""
190 # Error when no build target provided.
191 in_proto = self._InputProto()
192 out_proto = self._OutputProto()
193 with self.assertRaises(cros_build_lib.DieSystemExit):
194 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
195 self.api_config)
196
197 # Valid when board is specified.
198 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot',
199 return_value='/path/to/sysroot/tar.bz')
200 in_proto = self._InputProto(build_target='board')
201 out_proto = self._OutputProto()
202 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
203 self.api_config)
204 patch.assert_called_once()
205
206
Michael Mortensen3f6b4bd2020-02-07 14:16:43 -0700207class GenerateArchiveTest(cros_test_lib.MockTempDirTestCase,
208 api_config.ApiConfigMixin):
209 """GenerateArchive function tests."""
210
211 def setUp(self):
212 self.chroot_path = '/path/to/chroot'
213 self.board = 'board'
214
215 def _InputProto(self, build_target=None, chroot_path=None, pkg_list=None):
216 """Helper to build and input proto instance."""
217 # pkg_list will be a list of category/package strings such as
218 # ['virtual/target-fuzzers'].
219 if pkg_list:
220 package_list = []
221 for pkg in pkg_list:
222 pkg_string_parts = pkg.split('/')
223 package_info = common_pb2.PackageInfo(
224 category=pkg_string_parts[0],
225 package_name=pkg_string_parts[1])
226 package_list.append(package_info)
227 else:
228 package_list = []
229
230 return sysroot_pb2.SysrootGenerateArchiveRequest(
231 build_target={'name': build_target},
232 chroot={'path': chroot_path},
233 packages=package_list)
234
235 def _OutputProto(self):
236 """Helper to build output proto instance."""
237 return sysroot_pb2.SysrootGenerateArchiveResponse()
238
239 def testValidateOnly(self):
240 """Sanity check that a validate only call does not execute any logic."""
241 patch = self.PatchObject(sysroot_service, 'GenerateArchive')
242
243 in_proto = self._InputProto(build_target=self.board,
244 chroot_path=self.chroot_path,
245 pkg_list=['virtual/target-fuzzers'])
246 sysroot_controller.GenerateArchive(in_proto, self._OutputProto(),
247 self.validate_only_config)
248 patch.assert_not_called()
249
250 def testMockCall(self):
251 """Sanity check that a mock call does not execute any logic."""
252 patch = self.PatchObject(sysroot_service, 'GenerateArchive')
253
254 in_proto = self._InputProto(build_target=self.board,
255 chroot_path=self.chroot_path,
256 pkg_list=['virtual/target-fuzzers'])
257 sysroot_controller.GenerateArchive(in_proto,
258 self._OutputProto(),
259 self.mock_call_config)
260 patch.assert_not_called()
261
262 def testArgumentValidation(self):
263 """Test the input argument validation."""
264 # Error when no build target provided.
265 in_proto = self._InputProto()
266 out_proto = self._OutputProto()
267 with self.assertRaises(cros_build_lib.DieSystemExit):
268 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
269
270 # Error when packages is not specified.
271 in_proto = self._InputProto(build_target='board',
272 chroot_path=self.chroot_path)
273 with self.assertRaises(cros_build_lib.DieSystemExit):
274 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
275
276 # Valid when board, chroot path, and package are specified.
277 patch = self.PatchObject(sysroot_service, 'GenerateArchive',
278 return_value='/path/to/sysroot/tar.bz')
279 in_proto = self._InputProto(build_target='board',
280 chroot_path=self.chroot_path,
281 pkg_list=['virtual/target-fuzzers'])
282 out_proto = self._OutputProto()
283 sysroot_controller.GenerateArchive(in_proto, out_proto, self.api_config)
284 patch.assert_called_once()
285
286
Alex Klein231d2da2019-07-22 16:44:45 -0600287class InstallToolchainTest(cros_test_lib.MockTempDirTestCase,
288 api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -0700289 """Install toolchain function tests."""
290
291 def setUp(self):
292 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600293 # Avoid running the portageq command.
294 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleinda35fcf2019-03-07 16:01:15 -0700295 self.board = 'board'
296 self.sysroot = os.path.join(self.tempdir, 'board')
297 self.invalid_sysroot = os.path.join(self.tempdir, 'invalid', 'sysroot')
298 osutils.SafeMakedirs(self.sysroot)
299
300 def _InputProto(self, build_target=None, sysroot_path=None,
301 compile_source=False):
Alex Kleind4e1e422019-03-18 16:00:41 -0600302 """Helper to build an input proto instance."""
Alex Kleinda35fcf2019-03-07 16:01:15 -0700303 proto = sysroot_pb2.InstallToolchainRequest()
304 if build_target:
305 proto.sysroot.build_target.name = build_target
306 if sysroot_path:
307 proto.sysroot.path = sysroot_path
308 if compile_source:
309 proto.flags.compile_source = compile_source
310
311 return proto
312
313 def _OutputProto(self):
314 """Helper to build output proto instance."""
315 return sysroot_pb2.InstallToolchainResponse()
316
Alex Klein231d2da2019-07-22 16:44:45 -0600317 def testValidateOnly(self):
318 """Sanity check that a validate only call does not execute any logic."""
319 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
320
321 in_proto = self._InputProto(build_target=self.board,
322 sysroot_path=self.sysroot)
323 sysroot_controller.InstallToolchain(in_proto, self._OutputProto(),
324 self.validate_only_config)
325 patch.assert_not_called()
326
Alex Klein076841b2019-08-29 15:19:39 -0600327 def testMockCall(self):
328 """Sanity check that a mock call does not execute any logic."""
329 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
330 request = self._InputProto()
331 response = self._OutputProto()
332
333 rc = sysroot_controller.InstallToolchain(request, response,
334 self.mock_call_config)
335
336 patch.assert_not_called()
337 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
338
339 def testMockError(self):
340 """Sanity check that a mock error does not execute any logic."""
341 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
342 request = self._InputProto()
343 response = self._OutputProto()
344
345 rc = sysroot_controller.InstallToolchain(request, response,
346 self.mock_error_config)
347
348 patch.assert_not_called()
349 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
350 self.assertTrue(response.failed_packages)
351
Alex Kleinda35fcf2019-03-07 16:01:15 -0700352 def testArgumentValidation(self):
353 """Test the argument validation."""
354 # Test errors on missing inputs.
355 out_proto = self._OutputProto()
356 # Both missing.
357 in_proto = self._InputProto()
358 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600359 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700360
361 # Sysroot path missing.
362 in_proto = self._InputProto(build_target=self.board)
363 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600364 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700365
366 # Build target name missing.
367 in_proto = self._InputProto(sysroot_path=self.sysroot)
368 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600369 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700370
371 # Both provided, but invalid sysroot path.
372 in_proto = self._InputProto(build_target=self.board,
373 sysroot_path=self.invalid_sysroot)
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 def testSuccessOutputHandling(self):
378 """Test the output is processed and recorded correctly."""
379 self.PatchObject(sysroot_service, 'InstallToolchain')
380 out_proto = self._OutputProto()
381 in_proto = self._InputProto(build_target=self.board,
382 sysroot_path=self.sysroot)
383
Alex Klein231d2da2019-07-22 16:44:45 -0600384 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
385 self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700386 self.assertFalse(rc)
387 self.assertFalse(out_proto.failed_packages)
388
389
390 def testErrorOutputHandling(self):
391 """Test the error output is processed and recorded correctly."""
392 out_proto = self._OutputProto()
393 in_proto = self._InputProto(build_target=self.board,
394 sysroot_path=self.sysroot)
395
396 err_pkgs = ['cat/pkg', 'cat2/pkg2']
397 err_cpvs = [portage_util.SplitCPV(pkg, strict=False) for pkg in err_pkgs]
398 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
399 err = sysroot_lib.ToolchainInstallError('Error',
400 cros_build_lib.CommandResult(),
401 tc_info=err_cpvs)
402 self.PatchObject(sysroot_service, 'InstallToolchain', side_effect=err)
403
Alex Klein231d2da2019-07-22 16:44:45 -0600404 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
405 self.api_config)
Alex Klein8cb365a2019-05-15 16:24:53 -0600406 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700407 self.assertTrue(out_proto.failed_packages)
408 for package in out_proto.failed_packages:
409 cat_pkg = (package.category, package.package_name)
410 self.assertIn(cat_pkg, expected)
Alex Kleind4e1e422019-03-18 16:00:41 -0600411
412
Alex Klein231d2da2019-07-22 16:44:45 -0600413class InstallPackagesTest(cros_test_lib.MockTempDirTestCase,
414 api_config.ApiConfigMixin):
Alex Kleind4e1e422019-03-18 16:00:41 -0600415 """InstallPackages tests."""
416
417 def setUp(self):
418 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600419 # Avoid running the portageq command.
420 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleind4e1e422019-03-18 16:00:41 -0600421 self.build_target = 'board'
422 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
423 osutils.SafeMakedirs(self.sysroot)
Michael Mortensen798ee192020-01-17 13:04:43 -0700424 # Set up goma directories.
425 self.goma_dir = os.path.join(self.tempdir, 'goma_dir')
426 osutils.SafeMakedirs(self.goma_dir)
427 self.goma_out_dir = os.path.join(self.tempdir, 'goma_out_dir')
428 osutils.SafeMakedirs(self.goma_out_dir)
Michael Mortensen4ccfb082020-01-22 16:24:03 -0700429 os.environ['GLOG_log_dir'] = self.goma_dir
Alex Kleind4e1e422019-03-18 16:00:41 -0600430
431 def _InputProto(self, build_target=None, sysroot_path=None,
Michael Mortensen798ee192020-01-17 13:04:43 -0700432 build_source=False, goma_dir=None, goma_log_dir=None,
433 goma_stats_file=None, goma_counterz_file=None):
Alex Kleind4e1e422019-03-18 16:00:41 -0600434 """Helper to build an input proto instance."""
435 instance = sysroot_pb2.InstallPackagesRequest()
436
437 if build_target:
438 instance.sysroot.build_target.name = build_target
439 if sysroot_path:
440 instance.sysroot.path = sysroot_path
441 if build_source:
442 instance.flags.build_source = build_source
Michael Mortensen798ee192020-01-17 13:04:43 -0700443 if goma_dir:
444 instance.goma_config.goma_dir = goma_dir
445 if goma_log_dir:
446 instance.goma_config.log_dir.dir = goma_log_dir
447 if goma_stats_file:
448 instance.goma_config.stats_file = goma_stats_file
449 if goma_counterz_file:
450 instance.goma_config.counterz_file = goma_counterz_file
Alex Kleind4e1e422019-03-18 16:00:41 -0600451
452 return instance
453
454 def _OutputProto(self):
455 """Helper to build an empty output proto instance."""
456 return sysroot_pb2.InstallPackagesResponse()
457
Michael Mortensen798ee192020-01-17 13:04:43 -0700458 def _CreateGomaLogFile(self, goma_log_dir, name, timestamp):
459 """Creates a log file for testing.
460
461 Args:
462 goma_log_dir (str): Directory where the file will be created.
463 name (str): Log file 'base' name that is combined with the timestamp.
464 timestamp (datetime): timestamp that is written to the file.
465 """
466 path = os.path.join(
467 goma_log_dir,
468 '%s.host.log.INFO.%s' % (name, timestamp.strftime('%Y%m%d-%H%M%S.%f')))
469 osutils.WriteFile(
470 path,
471 timestamp.strftime('Goma log file created at: %Y/%m/%d %H:%M:%S'))
472
Alex Klein231d2da2019-07-22 16:44:45 -0600473 def testValidateOnly(self):
474 """Sanity check that a validate only call does not execute any logic."""
475 patch = self.PatchObject(sysroot_service, 'BuildPackages')
476
477 in_proto = self._InputProto(build_target=self.build_target,
478 sysroot_path=self.sysroot)
479 sysroot_controller.InstallPackages(in_proto, self._OutputProto(),
480 self.validate_only_config)
481 patch.assert_not_called()
482
Alex Klein076841b2019-08-29 15:19:39 -0600483 def testMockCall(self):
484 """Sanity check that a mock call does not execute any logic."""
485 patch = self.PatchObject(sysroot_service, 'BuildPackages')
486 request = self._InputProto()
487 response = self._OutputProto()
488
489 rc = sysroot_controller.InstallPackages(request, response,
490 self.mock_call_config)
491
492 patch.assert_not_called()
493 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
494
495 def testMockError(self):
496 """Sanity check that a mock error does not execute any logic."""
497 patch = self.PatchObject(sysroot_service, 'BuildPackages')
498 request = self._InputProto()
499 response = self._OutputProto()
500
501 rc = sysroot_controller.InstallPackages(request, response,
502 self.mock_error_config)
503
504 patch.assert_not_called()
505 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
506 self.assertTrue(response.failed_packages)
507
Alex Kleind4e1e422019-03-18 16:00:41 -0600508 def testArgumentValidationAllMissing(self):
509 """Test missing all arguments."""
510 out_proto = self._OutputProto()
511 in_proto = self._InputProto()
512 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600513 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600514
515 def testArgumentValidationNoSysroot(self):
516 """Test missing sysroot path."""
517 out_proto = self._OutputProto()
518 in_proto = self._InputProto(build_target=self.build_target)
519 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600520 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600521
522 def testArgumentValidationNoBuildTarget(self):
523 """Test missing build target name."""
524 out_proto = self._OutputProto()
525 in_proto = self._InputProto(sysroot_path=self.sysroot)
526 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600527 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600528
529 def testArgumentValidationInvalidSysroot(self):
530 """Test sysroot that hasn't had the toolchain installed."""
531 out_proto = self._OutputProto()
532 in_proto = self._InputProto(build_target=self.build_target,
533 sysroot_path=self.sysroot)
534 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
535 return_value=False)
536 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600537 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600538
539 def testSuccessOutputHandling(self):
540 """Test successful call output handling."""
541 # Prevent argument validation error.
542 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
543 return_value=True)
544
545 in_proto = self._InputProto(build_target=self.build_target,
546 sysroot_path=self.sysroot)
547 out_proto = self._OutputProto()
548 self.PatchObject(sysroot_service, 'BuildPackages')
549
Alex Klein231d2da2019-07-22 16:44:45 -0600550 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
551 self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600552 self.assertFalse(rc)
553 self.assertFalse(out_proto.failed_packages)
554
Michael Mortensen798ee192020-01-17 13:04:43 -0700555 def testSuccessWithGomaLogs(self):
556 """Test successful call with goma."""
557 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
558 datetime.datetime(2018, 9, 21, 12, 0, 0))
559 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
560 datetime.datetime(2018, 9, 21, 12, 1, 0))
561 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
562 datetime.datetime(2018, 9, 21, 12, 2, 0))
563
564 # Prevent argument validation error.
565 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
566 return_value=True)
567
568 in_proto = self._InputProto(build_target=self.build_target,
569 sysroot_path=self.sysroot,
570 goma_dir=self.goma_dir,
571 goma_log_dir=self.goma_out_dir)
572
573 out_proto = self._OutputProto()
574 self.PatchObject(sysroot_service, 'BuildPackages')
575
576 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
577 self.api_config)
578 self.assertFalse(rc)
579 self.assertFalse(out_proto.failed_packages)
580 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
581 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
582 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
583 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
584
585 def testSuccessWithGomaLogsAndStatsCounterzFiles(self):
586 """Test successful call with goma including stats and counterz files."""
587 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
588 datetime.datetime(2018, 9, 21, 12, 0, 0))
589 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
590 datetime.datetime(2018, 9, 21, 12, 1, 0))
591 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
592 datetime.datetime(2018, 9, 21, 12, 2, 0))
593 # Create stats and counterz files.
594 osutils.WriteFile(os.path.join(self.goma_dir, 'stats.binaryproto'),
595 'File: stats.binaryproto')
596 osutils.WriteFile(os.path.join(self.goma_dir, 'counterz.binaryproto'),
597 'File: counterz.binaryproto')
598
599 # Prevent argument validation error.
600 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
601 return_value=True)
602
603 in_proto = self._InputProto(build_target=self.build_target,
604 sysroot_path=self.sysroot,
605 goma_dir=self.goma_dir,
606 goma_log_dir=self.goma_out_dir,
607 goma_stats_file='stats.binaryproto',
608 goma_counterz_file='counterz.binaryproto')
609
610 out_proto = self._OutputProto()
611 self.PatchObject(sysroot_service, 'BuildPackages')
612
613 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
614 self.api_config)
615 self.assertFalse(rc)
616 self.assertFalse(out_proto.failed_packages)
617 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
618 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
619 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
620 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
621 # Verify that the output dir has 5 files -- since there should be 3 log
622 # files, the stats file, and the counterz file.
623 output_files = os.listdir(self.goma_out_dir)
624 self.assertCountEqual(output_files, [
625 'stats.binaryproto',
626 'counterz.binaryproto',
627 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
628 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
629 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
Michael Mortensen1c7439c2020-01-24 14:43:19 -0700630 self.assertEqual(out_proto.goma_artifacts.counterz_file,
631 'counterz.binaryproto')
632 self.assertEqual(out_proto.goma_artifacts.stats_file,
633 'stats.binaryproto')
Michael Mortensen798ee192020-01-17 13:04:43 -0700634
635 def testFailureMissingGomaStatsCounterzFiles(self):
636 """Test successful call with goma including stats and counterz files."""
637 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
638 datetime.datetime(2018, 9, 21, 12, 0, 0))
639 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
640 datetime.datetime(2018, 9, 21, 12, 1, 0))
641 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
642 datetime.datetime(2018, 9, 21, 12, 2, 0))
643 # Note that stats and counterz files are not created, but are specified in
644 # the proto below.
645
646 # Prevent argument validation error.
647 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
648 return_value=True)
649
650 in_proto = self._InputProto(build_target=self.build_target,
651 sysroot_path=self.sysroot,
652 goma_dir=self.goma_dir,
653 goma_log_dir=self.goma_out_dir,
654 goma_stats_file='stats.binaryproto',
655 goma_counterz_file='counterz.binaryproto')
656
657 out_proto = self._OutputProto()
658 self.PatchObject(sysroot_service, 'BuildPackages')
659
Michael Mortensen1d6d5b02020-01-22 07:33:50 -0700660 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
661 self.api_config)
662 self.assertFalse(rc)
663 self.assertFalse(out_proto.failed_packages)
664 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
665 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
666 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
667 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
668 self.assertFalse(out_proto.goma_artifacts.counterz_file)
669 self.assertFalse(out_proto.goma_artifacts.stats_file)
Michael Mortensen798ee192020-01-17 13:04:43 -0700670
Alex Kleind4e1e422019-03-18 16:00:41 -0600671 def testFailureOutputHandling(self):
672 """Test failed package handling."""
673 # Prevent argument validation error.
674 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
675 return_value=True)
676
677 in_proto = self._InputProto(build_target=self.build_target,
678 sysroot_path=self.sysroot)
679 out_proto = self._OutputProto()
680
681 # Failed package info and expected list for verification.
682 err_pkgs = ['cat/pkg', 'cat2/pkg2']
683 err_cpvs = [portage_util.SplitCPV(cpv, strict=False) for cpv in err_pkgs]
684 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
685
686 # Force error to be raised with the packages.
687 error = sysroot_lib.PackageInstallError('Error',
688 cros_build_lib.CommandResult(),
689 packages=err_cpvs)
690 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
691
Alex Klein231d2da2019-07-22 16:44:45 -0600692 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
693 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600694 # This needs to return 2 to indicate the available error response.
695 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleind4e1e422019-03-18 16:00:41 -0600696 for package in out_proto.failed_packages:
697 cat_pkg = (package.category, package.package_name)
698 self.assertIn(cat_pkg, expected)
Alex Klein2557b4f2019-07-11 14:34:00 -0600699
700 def testNoPackageFailureOutputHandling(self):
701 """Test failure handling without packages to report."""
702 # Prevent argument validation error.
703 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
704 return_value=True)
705
706 in_proto = self._InputProto(build_target=self.build_target,
707 sysroot_path=self.sysroot)
708 out_proto = self._OutputProto()
709
710 # Force error to be raised with no packages.
711 error = sysroot_lib.PackageInstallError('Error',
712 cros_build_lib.CommandResult(),
713 packages=[])
714 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
715
Alex Klein231d2da2019-07-22 16:44:45 -0600716 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
717 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600718 # All we really care about is it's not 0 or 2 (response available), so
719 # test for that rather than a specific return code.
720 self.assertTrue(rc)
721 self.assertNotEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE,
722 rc)