blob: e16c44ce688a091575ae4574f5e0c69c4bb885df [file] [log] [blame]
Alex Kleinda35fcf2019-03-07 16:01:15 -07001# -*- coding: utf-8 -*-
2# Copyright 2019 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Sysroot controller tests."""
7
8from __future__ import print_function
9
Michael Mortensen798ee192020-01-17 13:04:43 -070010import datetime
Alex Kleinda35fcf2019-03-07 16:01:15 -070011import os
12
Alex Klein231d2da2019-07-22 16:44:45 -060013from chromite.api import api_config
Alex Klein8cb365a2019-05-15 16:24:53 -060014from chromite.api import controller
Alex Kleinda35fcf2019-03-07 16:01:15 -070015from chromite.api.controller import sysroot as sysroot_controller
16from chromite.api.gen.chromite.api import sysroot_pb2
17from chromite.lib import build_target_util
18from chromite.lib import cros_build_lib
19from chromite.lib import cros_test_lib
Michael Mortensen798ee192020-01-17 13:04:43 -070020from chromite.lib import goma_lib
Alex Kleinda35fcf2019-03-07 16:01:15 -070021from chromite.lib import osutils
22from chromite.lib import portage_util
23from chromite.lib import sysroot_lib
24from chromite.service import sysroot as sysroot_service
25
26
Alex Klein231d2da2019-07-22 16:44:45 -060027class CreateTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -070028 """Create function tests."""
29
30 def _InputProto(self, build_target=None, profile=None, replace=False,
31 current=False):
32 """Helper to build and input proto instance."""
33 proto = sysroot_pb2.SysrootCreateRequest()
34 if build_target:
35 proto.build_target.name = build_target
36 if profile:
37 proto.profile.name = profile
38 if replace:
39 proto.flags.replace = replace
40 if current:
41 proto.flags.chroot_current = current
42
43 return proto
44
45 def _OutputProto(self):
46 """Helper to build output proto instance."""
47 return sysroot_pb2.SysrootCreateResponse()
48
Alex Klein231d2da2019-07-22 16:44:45 -060049 def testValidateOnly(self):
50 """Sanity check that a validate only call does not execute any logic."""
51 patch = self.PatchObject(sysroot_service, 'Create')
52
53 board = 'board'
54 profile = None
55 force = False
56 upgrade_chroot = True
57 in_proto = self._InputProto(build_target=board, profile=profile,
58 replace=force, current=not upgrade_chroot)
59 sysroot_controller.Create(in_proto, self._OutputProto(),
60 self.validate_only_config)
61 patch.assert_not_called()
62
Alex Klein076841b2019-08-29 15:19:39 -060063 def testMockCall(self):
64 """Sanity check that a mock call does not execute any logic."""
65 patch = self.PatchObject(sysroot_service, 'Create')
66 request = self._InputProto()
67 response = self._OutputProto()
68
69 rc = sysroot_controller.Create(request, response, self.mock_call_config)
70
71 patch.assert_not_called()
72 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
73
74 def testMockError(self):
75 """Sanity check that a mock error does not execute any logic."""
76 patch = self.PatchObject(sysroot_service, 'Create')
77 request = self._InputProto()
78 response = self._OutputProto()
79
80 rc = sysroot_controller.Create(request, response, self.mock_error_config)
81
82 patch.assert_not_called()
83 self.assertEqual(controller.RETURN_CODE_UNRECOVERABLE, rc)
84
Alex Kleinda35fcf2019-03-07 16:01:15 -070085 def testArgumentValidation(self):
86 """Test the input argument validation."""
87 # Error when no name provided.
88 in_proto = self._InputProto()
89 out_proto = self._OutputProto()
90 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060091 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -070092
93 # Valid when board passed.
94 result = sysroot_lib.Sysroot('/sysroot/path')
95 patch = self.PatchObject(sysroot_service, 'Create', return_value=result)
96 in_proto = self._InputProto('board')
97 out_proto = self._OutputProto()
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 patch.assert_called_once()
100
101 def testArgumentHandling(self):
102 """Test the arguments get processed and passed correctly."""
103 sysroot_path = '/sysroot/path'
104
105 sysroot = sysroot_lib.Sysroot(sysroot_path)
106 create_patch = self.PatchObject(sysroot_service, 'Create',
107 return_value=sysroot)
108 target_patch = self.PatchObject(build_target_util, 'BuildTarget')
109 rc_patch = self.PatchObject(sysroot_service, 'SetupBoardRunConfig')
110
111 # Default values.
112 board = 'board'
113 profile = None
114 force = False
115 upgrade_chroot = True
116 in_proto = self._InputProto(build_target=board, profile=profile,
117 replace=force, current=not upgrade_chroot)
118 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600119 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700120
121 # Default value checks.
122 target_patch.assert_called_with(name=board, profile=profile)
123 rc_patch.assert_called_with(force=force, upgrade_chroot=upgrade_chroot)
124 self.assertEqual(board, out_proto.sysroot.build_target.name)
125 self.assertEqual(sysroot_path, out_proto.sysroot.path)
126
127 # Not default values.
128 create_patch.reset_mock()
129 board = 'board'
130 profile = 'profile'
131 force = True
132 upgrade_chroot = False
133 in_proto = self._InputProto(build_target=board, profile=profile,
134 replace=force, current=not upgrade_chroot)
135 out_proto = self._OutputProto()
Alex Klein231d2da2019-07-22 16:44:45 -0600136 sysroot_controller.Create(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700137
138 # Not default value checks.
139 target_patch.assert_called_with(name=board, profile=profile)
140 rc_patch.assert_called_with(force=force, upgrade_chroot=upgrade_chroot)
141 self.assertEqual(board, out_proto.sysroot.build_target.name)
142 self.assertEqual(sysroot_path, out_proto.sysroot.path)
143
144
Michael Mortensen98592f62019-09-27 13:34:18 -0600145class CreateSimpleChromeSysrootTest(cros_test_lib.MockTempDirTestCase,
146 api_config.ApiConfigMixin):
147 """CreateSimpleChromeSysroot function tests."""
148
149 def _InputProto(self, build_target=None, use_flags=None):
150 """Helper to build and input proto instance."""
151 proto = sysroot_pb2.CreateSimpleChromeSysrootRequest()
152 if build_target:
153 proto.build_target.name = build_target
154 if use_flags:
155 proto.use_flags = use_flags
156 return proto
157
158 def _OutputProto(self):
159 """Helper to build output proto instance."""
160 return sysroot_pb2.CreateSimpleChromeSysrootResponse()
161
162 def testValidateOnly(self):
163 """Sanity check that a validate only call does not execute any logic."""
164 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot')
165
166 board = 'board'
167 in_proto = self._InputProto(build_target=board, use_flags=[])
168 sysroot_controller.CreateSimpleChromeSysroot(in_proto, self._OutputProto(),
169 self.validate_only_config)
170 patch.assert_not_called()
171
Michael Mortensen3232ab32020-01-05 19:14:36 -0700172 def testMockCall(self):
173 """Sanity check that a mock call does not execute any logic."""
174 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot')
175
176 board = 'board'
177 in_proto = self._InputProto(build_target=board, use_flags=[])
178 rc = sysroot_controller.CreateSimpleChromeSysroot(in_proto,
179 self._OutputProto(),
180 self.mock_call_config)
181 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
182 patch.assert_not_called()
183
Michael Mortensen98592f62019-09-27 13:34:18 -0600184 def testArgumentValidation(self):
185 """Test the input argument validation."""
186 # Error when no build target provided.
187 in_proto = self._InputProto()
188 out_proto = self._OutputProto()
189 with self.assertRaises(cros_build_lib.DieSystemExit):
190 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
191 self.api_config)
192
193 # Valid when board is specified.
194 patch = self.PatchObject(sysroot_service, 'CreateSimpleChromeSysroot',
195 return_value='/path/to/sysroot/tar.bz')
196 in_proto = self._InputProto(build_target='board')
197 out_proto = self._OutputProto()
198 sysroot_controller.CreateSimpleChromeSysroot(in_proto, out_proto,
199 self.api_config)
200 patch.assert_called_once()
201
202
Alex Klein231d2da2019-07-22 16:44:45 -0600203class InstallToolchainTest(cros_test_lib.MockTempDirTestCase,
204 api_config.ApiConfigMixin):
Alex Kleinda35fcf2019-03-07 16:01:15 -0700205 """Install toolchain function tests."""
206
207 def setUp(self):
208 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600209 # Avoid running the portageq command.
210 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleinda35fcf2019-03-07 16:01:15 -0700211 self.board = 'board'
212 self.sysroot = os.path.join(self.tempdir, 'board')
213 self.invalid_sysroot = os.path.join(self.tempdir, 'invalid', 'sysroot')
214 osutils.SafeMakedirs(self.sysroot)
215
216 def _InputProto(self, build_target=None, sysroot_path=None,
217 compile_source=False):
Alex Kleind4e1e422019-03-18 16:00:41 -0600218 """Helper to build an input proto instance."""
Alex Kleinda35fcf2019-03-07 16:01:15 -0700219 proto = sysroot_pb2.InstallToolchainRequest()
220 if build_target:
221 proto.sysroot.build_target.name = build_target
222 if sysroot_path:
223 proto.sysroot.path = sysroot_path
224 if compile_source:
225 proto.flags.compile_source = compile_source
226
227 return proto
228
229 def _OutputProto(self):
230 """Helper to build output proto instance."""
231 return sysroot_pb2.InstallToolchainResponse()
232
Alex Klein231d2da2019-07-22 16:44:45 -0600233 def testValidateOnly(self):
234 """Sanity check that a validate only call does not execute any logic."""
235 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
236
237 in_proto = self._InputProto(build_target=self.board,
238 sysroot_path=self.sysroot)
239 sysroot_controller.InstallToolchain(in_proto, self._OutputProto(),
240 self.validate_only_config)
241 patch.assert_not_called()
242
Alex Klein076841b2019-08-29 15:19:39 -0600243 def testMockCall(self):
244 """Sanity check that a mock call does not execute any logic."""
245 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
246 request = self._InputProto()
247 response = self._OutputProto()
248
249 rc = sysroot_controller.InstallToolchain(request, response,
250 self.mock_call_config)
251
252 patch.assert_not_called()
253 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
254
255 def testMockError(self):
256 """Sanity check that a mock error does not execute any logic."""
257 patch = self.PatchObject(sysroot_service, 'InstallToolchain')
258 request = self._InputProto()
259 response = self._OutputProto()
260
261 rc = sysroot_controller.InstallToolchain(request, response,
262 self.mock_error_config)
263
264 patch.assert_not_called()
265 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
266 self.assertTrue(response.failed_packages)
267
Alex Kleinda35fcf2019-03-07 16:01:15 -0700268 def testArgumentValidation(self):
269 """Test the argument validation."""
270 # Test errors on missing inputs.
271 out_proto = self._OutputProto()
272 # Both missing.
273 in_proto = self._InputProto()
274 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600275 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700276
277 # Sysroot path missing.
278 in_proto = self._InputProto(build_target=self.board)
279 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600280 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700281
282 # Build target name missing.
283 in_proto = self._InputProto(sysroot_path=self.sysroot)
284 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600285 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700286
287 # Both provided, but invalid sysroot path.
288 in_proto = self._InputProto(build_target=self.board,
289 sysroot_path=self.invalid_sysroot)
290 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600291 sysroot_controller.InstallToolchain(in_proto, out_proto, self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700292
293 def testSuccessOutputHandling(self):
294 """Test the output is processed and recorded correctly."""
295 self.PatchObject(sysroot_service, 'InstallToolchain')
296 out_proto = self._OutputProto()
297 in_proto = self._InputProto(build_target=self.board,
298 sysroot_path=self.sysroot)
299
Alex Klein231d2da2019-07-22 16:44:45 -0600300 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
301 self.api_config)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700302 self.assertFalse(rc)
303 self.assertFalse(out_proto.failed_packages)
304
305
306 def testErrorOutputHandling(self):
307 """Test the error output is processed and recorded correctly."""
308 out_proto = self._OutputProto()
309 in_proto = self._InputProto(build_target=self.board,
310 sysroot_path=self.sysroot)
311
312 err_pkgs = ['cat/pkg', 'cat2/pkg2']
313 err_cpvs = [portage_util.SplitCPV(pkg, strict=False) for pkg in err_pkgs]
314 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
315 err = sysroot_lib.ToolchainInstallError('Error',
316 cros_build_lib.CommandResult(),
317 tc_info=err_cpvs)
318 self.PatchObject(sysroot_service, 'InstallToolchain', side_effect=err)
319
Alex Klein231d2da2019-07-22 16:44:45 -0600320 rc = sysroot_controller.InstallToolchain(in_proto, out_proto,
321 self.api_config)
Alex Klein8cb365a2019-05-15 16:24:53 -0600322 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleinda35fcf2019-03-07 16:01:15 -0700323 self.assertTrue(out_proto.failed_packages)
324 for package in out_proto.failed_packages:
325 cat_pkg = (package.category, package.package_name)
326 self.assertIn(cat_pkg, expected)
Alex Kleind4e1e422019-03-18 16:00:41 -0600327
328
Alex Klein231d2da2019-07-22 16:44:45 -0600329class InstallPackagesTest(cros_test_lib.MockTempDirTestCase,
330 api_config.ApiConfigMixin):
Alex Kleind4e1e422019-03-18 16:00:41 -0600331 """InstallPackages tests."""
332
333 def setUp(self):
334 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Kleina9d64602019-05-17 14:55:37 -0600335 # Avoid running the portageq command.
336 self.PatchObject(sysroot_controller, '_LogBinhost')
Alex Kleind4e1e422019-03-18 16:00:41 -0600337 self.build_target = 'board'
338 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
339 osutils.SafeMakedirs(self.sysroot)
Michael Mortensen798ee192020-01-17 13:04:43 -0700340 # Set up goma directories.
341 self.goma_dir = os.path.join(self.tempdir, 'goma_dir')
342 osutils.SafeMakedirs(self.goma_dir)
343 self.goma_out_dir = os.path.join(self.tempdir, 'goma_out_dir')
344 osutils.SafeMakedirs(self.goma_out_dir)
Alex Kleind4e1e422019-03-18 16:00:41 -0600345
346 def _InputProto(self, build_target=None, sysroot_path=None,
Michael Mortensen798ee192020-01-17 13:04:43 -0700347 build_source=False, goma_dir=None, goma_log_dir=None,
348 goma_stats_file=None, goma_counterz_file=None):
Alex Kleind4e1e422019-03-18 16:00:41 -0600349 """Helper to build an input proto instance."""
350 instance = sysroot_pb2.InstallPackagesRequest()
351
352 if build_target:
353 instance.sysroot.build_target.name = build_target
354 if sysroot_path:
355 instance.sysroot.path = sysroot_path
356 if build_source:
357 instance.flags.build_source = build_source
Michael Mortensen798ee192020-01-17 13:04:43 -0700358 if goma_dir:
359 instance.goma_config.goma_dir = goma_dir
360 if goma_log_dir:
361 instance.goma_config.log_dir.dir = goma_log_dir
362 if goma_stats_file:
363 instance.goma_config.stats_file = goma_stats_file
364 if goma_counterz_file:
365 instance.goma_config.counterz_file = goma_counterz_file
Alex Kleind4e1e422019-03-18 16:00:41 -0600366
367 return instance
368
369 def _OutputProto(self):
370 """Helper to build an empty output proto instance."""
371 return sysroot_pb2.InstallPackagesResponse()
372
Michael Mortensen798ee192020-01-17 13:04:43 -0700373 def _CreateGomaLogFile(self, goma_log_dir, name, timestamp):
374 """Creates a log file for testing.
375
376 Args:
377 goma_log_dir (str): Directory where the file will be created.
378 name (str): Log file 'base' name that is combined with the timestamp.
379 timestamp (datetime): timestamp that is written to the file.
380 """
381 path = os.path.join(
382 goma_log_dir,
383 '%s.host.log.INFO.%s' % (name, timestamp.strftime('%Y%m%d-%H%M%S.%f')))
384 osutils.WriteFile(
385 path,
386 timestamp.strftime('Goma log file created at: %Y/%m/%d %H:%M:%S'))
387
Alex Klein231d2da2019-07-22 16:44:45 -0600388 def testValidateOnly(self):
389 """Sanity check that a validate only call does not execute any logic."""
390 patch = self.PatchObject(sysroot_service, 'BuildPackages')
391
392 in_proto = self._InputProto(build_target=self.build_target,
393 sysroot_path=self.sysroot)
394 sysroot_controller.InstallPackages(in_proto, self._OutputProto(),
395 self.validate_only_config)
396 patch.assert_not_called()
397
Alex Klein076841b2019-08-29 15:19:39 -0600398 def testMockCall(self):
399 """Sanity check that a mock call does not execute any logic."""
400 patch = self.PatchObject(sysroot_service, 'BuildPackages')
401 request = self._InputProto()
402 response = self._OutputProto()
403
404 rc = sysroot_controller.InstallPackages(request, response,
405 self.mock_call_config)
406
407 patch.assert_not_called()
408 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
409
410 def testMockError(self):
411 """Sanity check that a mock error does not execute any logic."""
412 patch = self.PatchObject(sysroot_service, 'BuildPackages')
413 request = self._InputProto()
414 response = self._OutputProto()
415
416 rc = sysroot_controller.InstallPackages(request, response,
417 self.mock_error_config)
418
419 patch.assert_not_called()
420 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
421 self.assertTrue(response.failed_packages)
422
Alex Kleind4e1e422019-03-18 16:00:41 -0600423 def testArgumentValidationAllMissing(self):
424 """Test missing all arguments."""
425 out_proto = self._OutputProto()
426 in_proto = self._InputProto()
427 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600428 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600429
430 def testArgumentValidationNoSysroot(self):
431 """Test missing sysroot path."""
432 out_proto = self._OutputProto()
433 in_proto = self._InputProto(build_target=self.build_target)
434 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600435 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600436
437 def testArgumentValidationNoBuildTarget(self):
438 """Test missing build target name."""
439 out_proto = self._OutputProto()
440 in_proto = self._InputProto(sysroot_path=self.sysroot)
441 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600442 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600443
444 def testArgumentValidationInvalidSysroot(self):
445 """Test sysroot that hasn't had the toolchain installed."""
446 out_proto = self._OutputProto()
447 in_proto = self._InputProto(build_target=self.build_target,
448 sysroot_path=self.sysroot)
449 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
450 return_value=False)
451 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600452 sysroot_controller.InstallPackages(in_proto, out_proto, self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600453
454 def testSuccessOutputHandling(self):
455 """Test successful call output handling."""
456 # Prevent argument validation error.
457 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
458 return_value=True)
459
460 in_proto = self._InputProto(build_target=self.build_target,
461 sysroot_path=self.sysroot)
462 out_proto = self._OutputProto()
463 self.PatchObject(sysroot_service, 'BuildPackages')
464
Alex Klein231d2da2019-07-22 16:44:45 -0600465 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
466 self.api_config)
Alex Kleind4e1e422019-03-18 16:00:41 -0600467 self.assertFalse(rc)
468 self.assertFalse(out_proto.failed_packages)
469
Michael Mortensen798ee192020-01-17 13:04:43 -0700470 def testSuccessWithGomaLogs(self):
471 """Test successful call with goma."""
472 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
473 datetime.datetime(2018, 9, 21, 12, 0, 0))
474 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
475 datetime.datetime(2018, 9, 21, 12, 1, 0))
476 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
477 datetime.datetime(2018, 9, 21, 12, 2, 0))
478
479 # Prevent argument validation error.
480 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
481 return_value=True)
482
483 in_proto = self._InputProto(build_target=self.build_target,
484 sysroot_path=self.sysroot,
485 goma_dir=self.goma_dir,
486 goma_log_dir=self.goma_out_dir)
487
488 out_proto = self._OutputProto()
489 self.PatchObject(sysroot_service, 'BuildPackages')
490
491 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
492 self.api_config)
493 self.assertFalse(rc)
494 self.assertFalse(out_proto.failed_packages)
495 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
496 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
497 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
498 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
499
500 def testSuccessWithGomaLogsAndStatsCounterzFiles(self):
501 """Test successful call with goma including stats and counterz files."""
502 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
503 datetime.datetime(2018, 9, 21, 12, 0, 0))
504 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
505 datetime.datetime(2018, 9, 21, 12, 1, 0))
506 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
507 datetime.datetime(2018, 9, 21, 12, 2, 0))
508 # Create stats and counterz files.
509 osutils.WriteFile(os.path.join(self.goma_dir, 'stats.binaryproto'),
510 'File: stats.binaryproto')
511 osutils.WriteFile(os.path.join(self.goma_dir, 'counterz.binaryproto'),
512 'File: counterz.binaryproto')
513
514 # Prevent argument validation error.
515 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
516 return_value=True)
517
518 in_proto = self._InputProto(build_target=self.build_target,
519 sysroot_path=self.sysroot,
520 goma_dir=self.goma_dir,
521 goma_log_dir=self.goma_out_dir,
522 goma_stats_file='stats.binaryproto',
523 goma_counterz_file='counterz.binaryproto')
524
525 out_proto = self._OutputProto()
526 self.PatchObject(sysroot_service, 'BuildPackages')
527
528 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
529 self.api_config)
530 self.assertFalse(rc)
531 self.assertFalse(out_proto.failed_packages)
532 self.assertCountEqual(out_proto.goma_artifacts.log_files, [
533 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
534 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
535 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
536 # Verify that the output dir has 5 files -- since there should be 3 log
537 # files, the stats file, and the counterz file.
538 output_files = os.listdir(self.goma_out_dir)
539 self.assertCountEqual(output_files, [
540 'stats.binaryproto',
541 'counterz.binaryproto',
542 'compiler_proxy-subproc.host.log.INFO.20180921-120100.000000.gz',
543 'compiler_proxy.host.log.INFO.20180921-120000.000000.gz',
544 'gomacc.host.log.INFO.20180921-120200.000000.tar.gz'])
545
546 def testFailureMissingGomaStatsCounterzFiles(self):
547 """Test successful call with goma including stats and counterz files."""
548 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy',
549 datetime.datetime(2018, 9, 21, 12, 0, 0))
550 self._CreateGomaLogFile(self.goma_dir, 'compiler_proxy-subproc',
551 datetime.datetime(2018, 9, 21, 12, 1, 0))
552 self._CreateGomaLogFile(self.goma_dir, 'gomacc',
553 datetime.datetime(2018, 9, 21, 12, 2, 0))
554 # Note that stats and counterz files are not created, but are specified in
555 # the proto below.
556
557 # Prevent argument validation error.
558 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
559 return_value=True)
560
561 in_proto = self._InputProto(build_target=self.build_target,
562 sysroot_path=self.sysroot,
563 goma_dir=self.goma_dir,
564 goma_log_dir=self.goma_out_dir,
565 goma_stats_file='stats.binaryproto',
566 goma_counterz_file='counterz.binaryproto')
567
568 out_proto = self._OutputProto()
569 self.PatchObject(sysroot_service, 'BuildPackages')
570
571 with self.assertRaises(goma_lib.SpecifiedFileMissingError):
572 sysroot_controller.InstallPackages(in_proto, out_proto,
573 self.api_config)
574
Alex Kleind4e1e422019-03-18 16:00:41 -0600575 def testFailureOutputHandling(self):
576 """Test failed package handling."""
577 # Prevent argument validation error.
578 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
579 return_value=True)
580
581 in_proto = self._InputProto(build_target=self.build_target,
582 sysroot_path=self.sysroot)
583 out_proto = self._OutputProto()
584
585 # Failed package info and expected list for verification.
586 err_pkgs = ['cat/pkg', 'cat2/pkg2']
587 err_cpvs = [portage_util.SplitCPV(cpv, strict=False) for cpv in err_pkgs]
588 expected = [('cat', 'pkg'), ('cat2', 'pkg2')]
589
590 # Force error to be raised with the packages.
591 error = sysroot_lib.PackageInstallError('Error',
592 cros_build_lib.CommandResult(),
593 packages=err_cpvs)
594 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
595
Alex Klein231d2da2019-07-22 16:44:45 -0600596 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
597 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600598 # This needs to return 2 to indicate the available error response.
599 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleind4e1e422019-03-18 16:00:41 -0600600 for package in out_proto.failed_packages:
601 cat_pkg = (package.category, package.package_name)
602 self.assertIn(cat_pkg, expected)
Alex Klein2557b4f2019-07-11 14:34:00 -0600603
604 def testNoPackageFailureOutputHandling(self):
605 """Test failure handling without packages to report."""
606 # Prevent argument validation error.
607 self.PatchObject(sysroot_lib.Sysroot, 'IsToolchainInstalled',
608 return_value=True)
609
610 in_proto = self._InputProto(build_target=self.build_target,
611 sysroot_path=self.sysroot)
612 out_proto = self._OutputProto()
613
614 # Force error to be raised with no packages.
615 error = sysroot_lib.PackageInstallError('Error',
616 cros_build_lib.CommandResult(),
617 packages=[])
618 self.PatchObject(sysroot_service, 'BuildPackages', side_effect=error)
619
Alex Klein231d2da2019-07-22 16:44:45 -0600620 rc = sysroot_controller.InstallPackages(in_proto, out_proto,
621 self.api_config)
Alex Klein2557b4f2019-07-11 14:34:00 -0600622 # All we really care about is it's not 0 or 2 (response available), so
623 # test for that rather than a specific return code.
624 self.assertTrue(rc)
625 self.assertNotEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE,
626 rc)