blob: f76bd098b1077442a0a5405996bc7727479cc927 [file] [log] [blame]
Alex Kleina2e42c42019-04-17 16:13:19 -06001# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""The test controller tests."""
6
Alex Klein9f915782020-02-14 23:15:09 +00007import contextlib
Lizzy Presland4feb2372022-01-20 05:16:30 +00008import datetime
Mike Frysingeref94e4c2020-02-10 23:59:54 -05009import os
Mike Frysinger3bb61cb2022-04-14 16:07:44 -040010from pathlib import Path
Mike Frysinger40443592022-05-05 13:03:40 -040011from typing import Union
Mike Frysinger166fea02021-02-12 05:30:33 -050012from unittest import mock
Mike Frysingeref94e4c2020-02-10 23:59:54 -050013
Mike Frysinger1cc8f1f2022-04-28 22:40:40 -040014from chromite.third_party.google.protobuf import json_format
15
Alex Klein231d2da2019-07-22 16:44:45 -060016from chromite.api import api_config
Alex Klein8cb365a2019-05-15 16:24:53 -060017from chromite.api import controller
Lizzy Presland4feb2372022-01-20 05:16:30 +000018from chromite.api.controller import controller_util
Alex Kleina2e42c42019-04-17 16:13:19 -060019from chromite.api.controller import test as test_controller
20from chromite.api.gen.chromite.api import test_pb2
Mike Frysinger1cc8f1f2022-04-28 22:40:40 -040021from chromite.api.gen.chromiumos import common_pb2
Sean McAllister3834fef2021-10-08 15:45:18 -060022from chromite.api.gen.chromiumos.build.api import container_metadata_pb2
Jack Neusc9707c32021-07-23 21:48:54 +000023from chromite.lib import build_target_lib
Evan Hernandeze1e05d32019-07-19 12:32:18 -060024from chromite.lib import chroot_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060025from chromite.lib import cros_build_lib
26from chromite.lib import cros_test_lib
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060027from chromite.lib import image_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060028from chromite.lib import osutils
David Wellingc1433c22021-06-25 16:29:48 +000029from chromite.lib import sysroot_lib
Alex Klein18a60af2020-06-11 12:08:47 -060030from chromite.lib.parser import package_info
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060031from chromite.scripts import cros_set_lsb_release
32from chromite.service import test as test_service
Mike Frysingere652ba12019-09-08 00:57:43 -040033from chromite.utils import key_value_store
Alex Kleina2e42c42019-04-17 16:13:19 -060034
35
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -070036class DebugInfoTestTest(cros_test_lib.MockTempDirTestCase,
37 api_config.ApiConfigMixin):
38 """Tests for the DebugInfoTest function."""
39
40 def setUp(self):
41 self.board = 'board'
42 self.chroot_path = os.path.join(self.tempdir, 'chroot')
43 self.sysroot_path = '/build/board'
44 self.full_sysroot_path = os.path.join(self.chroot_path,
45 self.sysroot_path.lstrip(os.sep))
46 osutils.SafeMakedirs(self.full_sysroot_path)
47
48 def _GetInput(self, sysroot_path=None, build_target=None):
49 """Helper to build an input message instance."""
50 proto = test_pb2.DebugInfoTestRequest()
51 if sysroot_path:
52 proto.sysroot.path = sysroot_path
53 if build_target:
54 proto.sysroot.build_target.name = build_target
55 return proto
56
57 def _GetOutput(self):
58 """Helper to get an empty output message instance."""
59 return test_pb2.DebugInfoTestResponse()
60
61 def testValidateOnly(self):
62 """Sanity check that a validate only call does not execute any logic."""
63 patch = self.PatchObject(test_service, 'DebugInfoTest')
64 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
65 test_controller.DebugInfoTest(input_msg, self._GetOutput(),
66 self.validate_only_config)
67 patch.assert_not_called()
68
Michael Mortensen85d38402019-12-12 09:50:29 -070069 def testMockError(self):
70 """Test mock error call does not execute any logic, returns error."""
71 patch = self.PatchObject(test_service, 'DebugInfoTest')
72
73 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
74 rc = test_controller.DebugInfoTest(input_msg, self._GetOutput(),
75 self.mock_error_config)
76 patch.assert_not_called()
77 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
78
79 def testMockCall(self):
80 """Test mock call does not execute any logic, returns success."""
81 patch = self.PatchObject(test_service, 'DebugInfoTest')
82
83 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
84 rc = test_controller.DebugInfoTest(input_msg, self._GetOutput(),
85 self.mock_call_config)
86 patch.assert_not_called()
87 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
88
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -070089 def testNoBuildTargetNoSysrootFails(self):
90 """Test missing build target name and sysroot path fails."""
91 input_msg = self._GetInput()
92 output_msg = self._GetOutput()
93 with self.assertRaises(cros_build_lib.DieSystemExit):
94 test_controller.DebugInfoTest(input_msg, output_msg, self.api_config)
95
96 def testDebugInfoTest(self):
97 """Call DebugInfoTest with valid sysroot_path."""
98 request = self._GetInput(sysroot_path=self.full_sysroot_path)
99
100 test_controller.DebugInfoTest(request, self._GetOutput(), self.api_config)
101
102
Alex Klein231d2da2019-07-22 16:44:45 -0600103class BuildTargetUnitTestTest(cros_test_lib.MockTempDirTestCase,
104 api_config.ApiConfigMixin):
Alex Kleina2e42c42019-04-17 16:13:19 -0600105 """Tests for the UnitTest function."""
106
Lizzy Presland4feb2372022-01-20 05:16:30 +0000107 def setUp(self):
108 # Set up portage log directory.
109 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
110 osutils.SafeMakedirs(self.sysroot)
111 self.target_sysroot = sysroot_lib.Sysroot(self.sysroot)
112 self.portage_dir = os.path.join(self.tempdir, 'portage_logdir')
113 self.PatchObject(
114 sysroot_lib.Sysroot, 'portage_logdir', new=self.portage_dir)
115 osutils.SafeMakedirs(self.portage_dir)
116
Navil Perezc0b29a82020-07-07 14:17:48 +0000117 def _GetInput(self,
118 board=None,
119 result_path=None,
120 chroot_path=None,
121 cache_dir=None,
122 empty_sysroot=None,
123 packages=None,
Alex Kleinb64e5f82020-09-23 10:55:31 -0600124 blocklist=None):
Alex Kleina2e42c42019-04-17 16:13:19 -0600125 """Helper to build an input message instance."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000126 formatted_packages = []
127 for pkg in packages or []:
128 formatted_packages.append({
129 'category': pkg.category,
130 'package_name': pkg.package
131 })
Alex Kleinb64e5f82020-09-23 10:55:31 -0600132 formatted_blocklist = []
133 for pkg in blocklist or []:
134 formatted_blocklist.append({'category': pkg.category,
Alex Kleinf2674462019-05-16 16:47:24 -0600135 'package_name': pkg.package})
136
Mike Frysinger3bb61cb2022-04-14 16:07:44 -0400137 # Protobufs can't handle Path objects.
138 if isinstance(result_path, Path):
139 result_path = str(result_path)
140
Alex Kleina2e42c42019-04-17 16:13:19 -0600141 return test_pb2.BuildTargetUnitTestRequest(
142 build_target={'name': board}, result_path=result_path,
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600143 chroot={'path': chroot_path, 'cache_dir': cache_dir},
Alex Kleinf2674462019-05-16 16:47:24 -0600144 flags={'empty_sysroot': empty_sysroot},
Alex Klein64ac34c2020-09-23 10:21:33 -0600145 packages=formatted_packages,
Alex Klein157caf42021-07-01 14:36:43 -0600146 package_blocklist=formatted_blocklist,
Alex Kleina2e42c42019-04-17 16:13:19 -0600147 )
148
149 def _GetOutput(self):
150 """Helper to get an empty output message instance."""
151 return test_pb2.BuildTargetUnitTestResponse()
152
Mike Frysinger40443592022-05-05 13:03:40 -0400153 def _CreatePortageLogFile(self,
154 log_path: Union[str, os.PathLike],
155 pkg_info: package_info.PackageInfo,
156 timestamp: datetime.datetime) -> str:
Lizzy Presland4feb2372022-01-20 05:16:30 +0000157 """Creates a log file for testing for individual packages built by Portage.
158
159 Args:
Mike Frysinger40443592022-05-05 13:03:40 -0400160 log_path: The PORTAGE_LOGDIR path.
161 pkg_info: name components for log file.
162 timestamp: Timestamp used to name the file.
Lizzy Presland4feb2372022-01-20 05:16:30 +0000163 """
164 path = os.path.join(log_path,
165 f'{pkg_info.category}:{pkg_info.pvr}:' \
166 f'{timestamp.strftime("%Y%m%d-%H%M%S")}.log')
167 osutils.WriteFile(path,
168 f'Test log file for package {pkg_info.category}/'
169 f'{pkg_info.package} written to {path}')
170 return path
171
Alex Klein231d2da2019-07-22 16:44:45 -0600172 def testValidateOnly(self):
173 """Sanity check that a validate only call does not execute any logic."""
174 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
175
176 input_msg = self._GetInput(board='board', result_path=self.tempdir)
177 test_controller.BuildTargetUnitTest(input_msg, self._GetOutput(),
178 self.validate_only_config)
179 patch.assert_not_called()
180
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700181 def testMockCall(self):
182 """Test that a mock call does not execute logic, returns mocked value."""
183 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
184
185 input_msg = self._GetInput(board='board', result_path=self.tempdir)
186 response = self._GetOutput()
187 test_controller.BuildTargetUnitTest(input_msg, response,
188 self.mock_call_config)
189 patch.assert_not_called()
190 self.assertEqual(response.tarball_path,
191 os.path.join(input_msg.result_path, 'unit_tests.tar'))
192
193 def testMockError(self):
Michael Mortensen85d38402019-12-12 09:50:29 -0700194 """Test that a mock error does not execute logic, returns error."""
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700195 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
196
197 input_msg = self._GetInput(board='board', result_path=self.tempdir)
198 response = self._GetOutput()
199 rc = test_controller.BuildTargetUnitTest(input_msg, response,
200 self.mock_error_config)
201 patch.assert_not_called()
202 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
203 self.assertTrue(response.failed_packages)
204 self.assertEqual(response.failed_packages[0].category, 'foo')
205 self.assertEqual(response.failed_packages[0].package_name, 'bar')
206 self.assertEqual(response.failed_packages[1].category, 'cat')
207 self.assertEqual(response.failed_packages[1].package_name, 'pkg')
208
Alex Klein64ac34c2020-09-23 10:21:33 -0600209 def testInvalidPackageFails(self):
210 """Test missing result path fails."""
211 # Missing result_path.
212 pkg = package_info.PackageInfo(package='bar')
213 input_msg = self._GetInput(board='board', result_path=self.tempdir,
214 packages=[pkg])
215 output_msg = self._GetOutput()
216 with self.assertRaises(cros_build_lib.DieSystemExit):
217 test_controller.BuildTargetUnitTest(input_msg, output_msg,
218 self.api_config)
219
Alex Kleina2e42c42019-04-17 16:13:19 -0600220 def testPackageBuildFailure(self):
221 """Test handling of raised BuildPackageFailure."""
222 tempdir = osutils.TempDir(base_dir=self.tempdir)
223 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
224
Lizzy Presland4feb2372022-01-20 05:16:30 +0000225 pkgs = ['cat/pkg-1.0-r1', 'foo/bar-2.0-r1']
226 cpvrs = [package_info.parse(pkg) for pkg in pkgs]
Alex Kleina2e42c42019-04-17 16:13:19 -0600227 expected = [('cat', 'pkg'), ('foo', 'bar')]
Lizzy Presland4feb2372022-01-20 05:16:30 +0000228 new_logs = {}
229 for i, pkg in enumerate(pkgs):
230 self._CreatePortageLogFile(self.portage_dir, cpvrs[i],
231 datetime.datetime(2021, 6, 9, 13, 37, 0))
232 new_logs[pkg] = self._CreatePortageLogFile(self.portage_dir, cpvrs[i],
233 datetime.datetime(2021, 6, 9,
234 16, 20, 0))
Alex Kleina2e42c42019-04-17 16:13:19 -0600235
Alex Klein38c7d9e2019-05-08 09:31:19 -0600236 result = test_service.BuildTargetUnitTestResult(1, None)
Alex Kleinea0c89e2021-09-09 15:17:35 -0600237 result.failed_pkgs = [package_info.parse(p) for p in pkgs]
Alex Klein38c7d9e2019-05-08 09:31:19 -0600238 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600239
240 input_msg = self._GetInput(board='board', result_path=self.tempdir)
241 output_msg = self._GetOutput()
242
Alex Klein231d2da2019-07-22 16:44:45 -0600243 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
244 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600245
Alex Klein8cb365a2019-05-15 16:24:53 -0600246 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600247 self.assertTrue(output_msg.failed_packages)
Lizzy Presland4feb2372022-01-20 05:16:30 +0000248 self.assertTrue(output_msg.failed_package_data)
249 # TODO(b/206514844): remove when field is deleted
Alex Kleina2e42c42019-04-17 16:13:19 -0600250 failed = []
251 for pi in output_msg.failed_packages:
252 failed.append((pi.category, pi.package_name))
Mike Frysinger678735c2019-09-28 18:23:28 -0400253 self.assertCountEqual(expected, failed)
Alex Kleina2e42c42019-04-17 16:13:19 -0600254
Lizzy Presland4feb2372022-01-20 05:16:30 +0000255 failed_with_logs = []
256 for data in output_msg.failed_package_data:
257 failed_with_logs.append((data.name.category, data.name.package_name))
258 package = controller_util.deserialize_package_info(data.name)
259 self.assertEqual(data.log_path.path, new_logs[package.cpvr])
260 self.assertCountEqual(expected, failed_with_logs)
261
262
Alex Kleina2e42c42019-04-17 16:13:19 -0600263 def testOtherBuildScriptFailure(self):
264 """Test build script failure due to non-package emerge error."""
265 tempdir = osutils.TempDir(base_dir=self.tempdir)
266 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
267
Alex Klein38c7d9e2019-05-08 09:31:19 -0600268 result = test_service.BuildTargetUnitTestResult(1, None)
269 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600270
Alex Kleinf2674462019-05-16 16:47:24 -0600271 pkgs = ['foo/bar', 'cat/pkg']
Alex Kleinb64e5f82020-09-23 10:55:31 -0600272 blocklist = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Klein2e91e522022-01-14 09:22:03 -0700273 input_msg = self._GetInput(board='board', empty_sysroot=True,
274 blocklist=blocklist)
Alex Kleina2e42c42019-04-17 16:13:19 -0600275 output_msg = self._GetOutput()
276
Alex Klein231d2da2019-07-22 16:44:45 -0600277 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
278 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600279
Alex Klein8cb365a2019-05-15 16:24:53 -0600280 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600281 self.assertFalse(output_msg.failed_packages)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600282
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700283 def testBuildTargetUnitTest(self):
284 """Test BuildTargetUnitTest successful call."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000285 pkgs = ['foo/bar', 'cat/pkg']
Alex Klein18a60af2020-06-11 12:08:47 -0600286 packages = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Klein2e91e522022-01-14 09:22:03 -0700287 input_msg = self._GetInput(board='board', packages=packages)
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700288
289 result = test_service.BuildTargetUnitTestResult(0, None)
290 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
291
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700292 response = self._GetOutput()
293 test_controller.BuildTargetUnitTest(input_msg, response,
294 self.api_config)
Alex Klein2e91e522022-01-14 09:22:03 -0700295 self.assertFalse(response.failed_packages)
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700296
Evan Hernandez4e388a52019-05-01 12:16:33 -0600297
Sean McAllister17eed8d2021-09-21 10:41:16 -0600298class DockerConstraintsTest(cros_test_lib.MockTestCase):
299 """Tests for Docker argument constraints."""
300
301 def assertValid(self, output):
302 return output is None
303
304 def assertInvalid(self, output):
305 return not self.assertValid(output)
306
307 def testValidDockerTag(self):
308 """Check logic for validating docker tag format."""
309 # pylint: disable=protected-access
310
311 invalid_tags = [
312 '.invalid-tag',
313 '-invalid-tag',
314 'invalid-tag;',
315 'invalid'*100,
316 ]
317
318 for tag in invalid_tags:
319 self.assertInvalid(test_controller._ValidDockerTag(tag))
320
321 valid_tags = [
322 'valid-tag',
323 'valid-tag-',
324 'valid.tag.',
325 ]
326
327 for tag in valid_tags:
328 self.assertValid(test_controller._ValidDockerTag(tag))
329
330
331 def testValidDockerLabelKey(self):
332 """Check logic for validating docker label key format."""
333 # pylint: disable=protected-access
334
335 invalid_keys = [
336 'Invalid-keY',
337 'Invalid-key',
338 'invalid-keY',
339 'iNVALID-KEy',
340 'invalid_key',
341 'invalid-key;',
342 ]
343
344 for key in invalid_keys:
345 self.assertInvalid(test_controller._ValidDockerLabelKey(key))
346
347 valid_keys = [
348 'chromeos.valid-key',
349 'chromeos.valid-key-2',
350 ]
351
352 for key in valid_keys:
353 self.assertValid(test_controller._ValidDockerLabelKey(key))
354
355
Sean McAllister3834fef2021-10-08 15:45:18 -0600356class BuildTestServiceContainers(cros_test_lib.RunCommandTempDirTestCase,
David Wellingc1433c22021-06-25 16:29:48 +0000357 api_config.ApiConfigMixin):
C Shapiro91af1ce2021-06-17 12:42:09 -0500358 """Tests for the BuildTestServiceContainers function."""
359
360 def setUp(self):
361 self.request = test_pb2.BuildTestServiceContainersRequest(
362 chroot={'path': '/path/to/chroot'},
363 build_target={'name': 'build_target'},
David Wellingc1433c22021-06-25 16:29:48 +0000364 version='R93-14033.0.0',
C Shapiro91af1ce2021-06-17 12:42:09 -0500365 )
366
C Shapiro91af1ce2021-06-17 12:42:09 -0500367 def testSuccess(self):
368 """Check passing case with mocked cros_build_lib.run."""
Sean McAllister3834fef2021-10-08 15:45:18 -0600369
370 def ContainerMetadata():
371 """Return mocked ContainerImageInfo proto"""
372 metadata = container_metadata_pb2.ContainerImageInfo()
373 metadata.repository.hostname = 'gcr.io'
374 metadata.repository.project = 'chromeos-bot'
375 metadata.name = 'random-container-name'
376 metadata.digest = (
377 '09b730f8b6a862f9c2705cb3acf3554563325f5fca5c784bf5c98beb2e56f6db')
378 metadata.tags[:] = [
379 'staging-cq-amd64-generic.R96-1.2.3',
380 '8834106026340379089',
381 ]
382 return metadata
383
384 def WriteContainerMetadata(path):
385 """Write json formatted metadata to the given file."""
386 osutils.WriteFile(
387 path,
388 json_format.MessageToJson(ContainerMetadata()),
389 )
390
391 # Write out mocked container metadata to a temporary file.
392 output_path = os.path.join(self.tempdir, 'metadata.jsonpb')
393 self.rc.SetDefaultCmdResult(
394 returncode=0,
395 side_effect=lambda *_, **__: WriteContainerMetadata(output_path)
396 )
397
398 # Patch TempDir so that we always use this test's directory.
399 self.PatchObject(osutils.TempDir, '__enter__', return_value=self.tempdir)
C Shapiro91af1ce2021-06-17 12:42:09 -0500400
401 response = test_pb2.BuildTestServiceContainersResponse()
402 test_controller.BuildTestServiceContainers(
403 self.request,
404 response,
405 self.api_config)
Sean McAllister3834fef2021-10-08 15:45:18 -0600406
407 self.assertTrue(self.rc.called)
C Shapiro91af1ce2021-06-17 12:42:09 -0500408 for result in response.results:
409 self.assertEqual(result.WhichOneof('result'), 'success')
Sean McAllister3834fef2021-10-08 15:45:18 -0600410 self.assertEqual(result.success.image_info, ContainerMetadata())
C Shapiro91af1ce2021-06-17 12:42:09 -0500411
C Shapiro91af1ce2021-06-17 12:42:09 -0500412 def testFailure(self):
413 """Check failure case with mocked cros_build_lib.run."""
414 patch = self.PatchObject(
415 cros_build_lib, 'run',
416 return_value=cros_build_lib.CommandResult(returncode=1))
417
418 response = test_pb2.BuildTestServiceContainersResponse()
419 test_controller.BuildTestServiceContainers(
420 self.request,
421 response,
422 self.api_config)
423 patch.assert_called()
424 for result in response.results:
Derek Beckettcbe64c82022-05-05 15:00:18 -0700425 if 'beta' in result.name:
Derek Beckett2b89c6f2022-05-02 15:21:16 -0700426 self.assertEqual(result.WhichOneof('result'), 'success')
427 else:
428 self.assertEqual(result.WhichOneof('result'), 'failure')
C Shapiro91af1ce2021-06-17 12:42:09 -0500429
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700430class ChromiteUnitTestTest(cros_test_lib.MockTestCase,
431 api_config.ApiConfigMixin):
432 """Tests for the ChromiteInfoTest function."""
433
434 def setUp(self):
435 self.board = 'board'
436 self.chroot_path = '/path/to/chroot'
437
438 def _GetInput(self, chroot_path=None):
439 """Helper to build an input message instance."""
440 proto = test_pb2.ChromiteUnitTestRequest(
441 chroot={'path': chroot_path},
442 )
443 return proto
444
445 def _GetOutput(self):
446 """Helper to get an empty output message instance."""
447 return test_pb2.ChromiteUnitTestResponse()
448
449 def testValidateOnly(self):
450 """Sanity check that a validate only call does not execute any logic."""
451 patch = self.PatchObject(cros_build_lib, 'run')
452
453 input_msg = self._GetInput(chroot_path=self.chroot_path)
454 test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
455 self.validate_only_config)
456 patch.assert_not_called()
457
Michael Mortensen7a860eb2019-12-03 20:25:15 -0700458 def testMockError(self):
459 """Test mock error call does not execute any logic, returns error."""
460 patch = self.PatchObject(cros_build_lib, 'run')
461
462 input_msg = self._GetInput(chroot_path=self.chroot_path)
463 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
464 self.mock_error_config)
465 patch.assert_not_called()
466 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
467
468 def testMockCall(self):
469 """Test mock call does not execute any logic, returns success."""
470 patch = self.PatchObject(cros_build_lib, 'run')
471
472 input_msg = self._GetInput(chroot_path=self.chroot_path)
473 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
474 self.mock_call_config)
475 patch.assert_not_called()
476 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
477
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700478 def testChromiteUnitTest(self):
479 """Call ChromiteUnitTest with mocked cros_build_lib.run."""
480 request = self._GetInput(chroot_path=self.chroot_path)
481 patch = self.PatchObject(
482 cros_build_lib, 'run',
483 return_value=cros_build_lib.CommandResult(returncode=0))
484
485 test_controller.ChromiteUnitTest(request, self._GetOutput(),
486 self.api_config)
487 patch.assert_called_once()
488
489
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600490class CrosSigningTestTest(cros_test_lib.RunCommandTestCase,
491 api_config.ApiConfigMixin):
492 """CrosSigningTest tests."""
493
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700494 def setUp(self):
495 self.chroot_path = '/path/to/chroot'
496
497 def _GetInput(self, chroot_path=None):
498 """Helper to build an input message instance."""
499 proto = test_pb2.CrosSigningTestRequest(
500 chroot={'path': chroot_path},
501 )
502 return proto
503
504 def _GetOutput(self):
505 """Helper to get an empty output message instance."""
506 return test_pb2.CrosSigningTestResponse()
507
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600508 def testValidateOnly(self):
509 """Sanity check that a validate only call does not execute any logic."""
510 test_controller.CrosSigningTest(None, None, self.validate_only_config)
511 self.assertFalse(self.rc.call_count)
512
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700513 def testMockCall(self):
514 """Test mock call does not execute any logic, returns success."""
515 rc = test_controller.CrosSigningTest(None, None, self.mock_call_config)
516 self.assertFalse(self.rc.call_count)
517 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
518
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700519 def testCrosSigningTest(self):
520 """Call CrosSigningTest with mocked cros_build_lib.run."""
521 request = self._GetInput(chroot_path=self.chroot_path)
522 patch = self.PatchObject(
523 cros_build_lib, 'run',
524 return_value=cros_build_lib.CommandResult(returncode=0))
525
526 test_controller.CrosSigningTest(request, self._GetOutput(),
527 self.api_config)
528 patch.assert_called_once()
529
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600530
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600531class SimpleChromeWorkflowTestTest(cros_test_lib.MockTestCase,
532 api_config.ApiConfigMixin):
533 """Test the SimpleChromeWorkflowTest endpoint."""
534
535 @staticmethod
536 def _Output():
537 return test_pb2.SimpleChromeWorkflowTestResponse()
538
David Wellingc1433c22021-06-25 16:29:48 +0000539 def _Input(self,
540 sysroot_path=None,
541 build_target=None,
542 chrome_root=None,
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600543 goma_config=None):
544 proto = test_pb2.SimpleChromeWorkflowTestRequest()
545 if sysroot_path:
546 proto.sysroot.path = sysroot_path
547 if build_target:
548 proto.sysroot.build_target.name = build_target
549 if chrome_root:
550 proto.chrome_root = chrome_root
551 if goma_config:
552 proto.goma_config = goma_config
553 return proto
554
555 def setUp(self):
556 self.chrome_path = 'path/to/chrome'
557 self.sysroot_dir = 'build/board'
558 self.build_target = 'amd64'
559 self.mock_simple_chrome_workflow_test = self.PatchObject(
560 test_service, 'SimpleChromeWorkflowTest')
561
562 def testMissingBuildTarget(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700563 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600564 input_proto = self._Input(build_target=None, sysroot_path='/sysroot/dir',
565 chrome_root='/chrome/path')
566 with self.assertRaises(cros_build_lib.DieSystemExit):
567 test_controller.SimpleChromeWorkflowTest(input_proto, None,
568 self.api_config)
569
570 def testMissingSysrootPath(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700571 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600572 input_proto = self._Input(build_target='board', sysroot_path=None,
573 chrome_root='/chrome/path')
574 with self.assertRaises(cros_build_lib.DieSystemExit):
575 test_controller.SimpleChromeWorkflowTest(input_proto, None,
576 self.api_config)
577
578 def testMissingChromeRoot(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700579 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600580 input_proto = self._Input(build_target='board', sysroot_path='/sysroot/dir',
581 chrome_root=None)
582 with self.assertRaises(cros_build_lib.DieSystemExit):
583 test_controller.SimpleChromeWorkflowTest(input_proto, None,
584 self.api_config)
585
586 def testSimpleChromeWorkflowTest(self):
587 """Call SimpleChromeWorkflowTest with valid args and temp dir."""
588 request = self._Input(sysroot_path='sysroot_path', build_target='board',
589 chrome_root='/path/to/chrome')
590 response = self._Output()
591
592 test_controller.SimpleChromeWorkflowTest(request, response, self.api_config)
593 self.mock_simple_chrome_workflow_test.assert_called()
594
595 def testValidateOnly(self):
596 request = self._Input(sysroot_path='sysroot_path', build_target='board',
597 chrome_root='/path/to/chrome')
598 test_controller.SimpleChromeWorkflowTest(request, self._Output(),
599 self.validate_only_config)
600 self.mock_simple_chrome_workflow_test.assert_not_called()
601
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700602 def testMockCall(self):
603 """Test mock call does not execute any logic, returns success."""
604 patch = self.mock_simple_chrome_workflow_test = self.PatchObject(
605 test_service, 'SimpleChromeWorkflowTest')
606
607 request = self._Input(sysroot_path='sysroot_path', build_target='board',
608 chrome_root='/path/to/chrome')
609 rc = test_controller.SimpleChromeWorkflowTest(request, self._Output(),
610 self.mock_call_config)
611 patch.assert_not_called()
612 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
613
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600614
Alex Klein231d2da2019-07-22 16:44:45 -0600615class VmTestTest(cros_test_lib.RunCommandTestCase, api_config.ApiConfigMixin):
Evan Hernandez4e388a52019-05-01 12:16:33 -0600616 """Test the VmTest endpoint."""
617
618 def _GetInput(self, **kwargs):
619 values = dict(
620 build_target=common_pb2.BuildTarget(name='target'),
Alex Klein311b8022019-06-05 16:00:07 -0600621 vm_path=common_pb2.Path(path='/path/to/image.bin',
622 location=common_pb2.Path.INSIDE),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600623 test_harness=test_pb2.VmTestRequest.TAST,
624 vm_tests=[test_pb2.VmTestRequest.VmTest(pattern='suite')],
625 ssh_options=test_pb2.VmTestRequest.SshOptions(
Alex Klein231d2da2019-07-22 16:44:45 -0600626 port=1234, private_key_path={'path': '/path/to/id_rsa',
Alex Kleinaa705412019-06-04 15:00:30 -0600627 'location': common_pb2.Path.INSIDE}),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600628 )
629 values.update(kwargs)
630 return test_pb2.VmTestRequest(**values)
631
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700632 def _Output(self):
633 return test_pb2.VmTestResponse()
634
Alex Klein231d2da2019-07-22 16:44:45 -0600635 def testValidateOnly(self):
636 """Sanity check that a validate only call does not execute any logic."""
637 test_controller.VmTest(self._GetInput(), None, self.validate_only_config)
638 self.assertEqual(0, self.rc.call_count)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600639
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700640 def testMockCall(self):
641 """Test mock call does not execute any logic."""
642 patch = self.PatchObject(cros_build_lib, 'run')
643
644 request = self._GetInput()
645 response = self._Output()
646 # VmTest does not return a value, checking mocked value is flagged by lint.
647 test_controller.VmTest(request, response, self.mock_call_config)
648 patch.assert_not_called()
649
Evan Hernandez4e388a52019-05-01 12:16:33 -0600650 def testTastAllOptions(self):
651 """Test VmTest for Tast with all options set."""
Alex Klein231d2da2019-07-22 16:44:45 -0600652 test_controller.VmTest(self._GetInput(), None, self.api_config)
653 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700654 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600655 '--board', 'target',
656 '--image-path', '/path/to/image.bin',
657 '--tast', 'suite',
658 '--ssh-port', '1234',
659 '--private-key', '/path/to/id_rsa',
660 ])
661
662 def testAutotestAllOptions(self):
663 """Test VmTest for Autotest with all options set."""
664 input_proto = self._GetInput(test_harness=test_pb2.VmTestRequest.AUTOTEST)
Alex Klein231d2da2019-07-22 16:44:45 -0600665 test_controller.VmTest(input_proto, None, self.api_config)
666 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700667 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600668 '--board', 'target',
669 '--image-path', '/path/to/image.bin',
670 '--autotest', 'suite',
671 '--ssh-port', '1234',
672 '--private-key', '/path/to/id_rsa',
Greg Edelstondcb0e912020-08-31 11:09:40 -0600673 '--test_that-args=--allow-chrome-crashes',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600674 ])
675
676 def testMissingBuildTarget(self):
677 """Test VmTest dies when build_target not set."""
678 input_proto = self._GetInput(build_target=None)
679 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600680 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600681
682 def testMissingVmImage(self):
683 """Test VmTest dies when vm_image not set."""
Alex Klein311b8022019-06-05 16:00:07 -0600684 input_proto = self._GetInput(vm_path=None)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600685 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600686 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600687
688 def testMissingTestHarness(self):
689 """Test VmTest dies when test_harness not specified."""
690 input_proto = self._GetInput(
691 test_harness=test_pb2.VmTestRequest.UNSPECIFIED)
692 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600693 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600694
695 def testMissingVmTests(self):
696 """Test VmTest dies when vm_tests not set."""
697 input_proto = self._GetInput(vm_tests=[])
698 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600699 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600700
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700701 def testVmTest(self):
702 """Call VmTest with valid args and temp dir."""
703 request = self._GetInput()
704 response = self._Output()
705 patch = self.PatchObject(
706 cros_build_lib, 'run',
707 return_value=cros_build_lib.CommandResult(returncode=0))
708
709 test_controller.VmTest(request, response, self.api_config)
710 patch.assert_called()
711
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600712
Alex Klein231d2da2019-07-22 16:44:45 -0600713class MoblabVmTestTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600714 """Test the MoblabVmTest endpoint."""
715
716 @staticmethod
717 def _Payload(path):
718 return test_pb2.MoblabVmTestRequest.Payload(
719 path=common_pb2.Path(path=path))
720
721 @staticmethod
722 def _Output():
723 return test_pb2.MoblabVmTestResponse()
724
725 def _Input(self):
726 return test_pb2.MoblabVmTestRequest(
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600727 chroot=common_pb2.Chroot(path=self.chroot_dir),
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600728 image_payload=self._Payload(self.image_payload_dir),
729 cache_payloads=[self._Payload(self.autotest_payload_dir)])
730
731 def setUp(self):
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600732 self.chroot_dir = '/chroot'
733 self.chroot_tmp_dir = '/chroot/tmp'
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600734 self.image_payload_dir = '/payloads/image'
735 self.autotest_payload_dir = '/payloads/autotest'
736 self.builder = 'moblab-generic-vm/R12-3.4.5-67.890'
737 self.image_cache_dir = '/mnt/moblab/cache'
738 self.image_mount_dir = '/mnt/image'
739
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600740 self.PatchObject(chroot_lib.Chroot, 'tempdir', osutils.TempDir)
Evan Hernandez655e8042019-06-13 12:50:44 -0600741
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600742 self.mock_create_moblab_vms = self.PatchObject(
743 test_service, 'CreateMoblabVm')
744 self.mock_prepare_moblab_vm_image_cache = self.PatchObject(
745 test_service, 'PrepareMoblabVmImageCache',
746 return_value=self.image_cache_dir)
747 self.mock_run_moblab_vm_tests = self.PatchObject(
748 test_service, 'RunMoblabVmTest')
749 self.mock_validate_moblab_vm_tests = self.PatchObject(
750 test_service, 'ValidateMoblabVmTest')
751
752 @contextlib.contextmanager
Alex Klein38c7d9e2019-05-08 09:31:19 -0600753 def MockLoopbackPartitions(*_args, **_kwargs):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600754 mount = mock.MagicMock()
Evan Hernandez40ee7452019-06-13 12:51:43 -0600755 mount.Mount.return_value = [self.image_mount_dir]
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600756 yield mount
Alex Klein231d2da2019-07-22 16:44:45 -0600757
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600758 self.PatchObject(image_lib, 'LoopbackPartitions', MockLoopbackPartitions)
759
Alex Klein231d2da2019-07-22 16:44:45 -0600760 def testValidateOnly(self):
761 """Sanity check that a validate only call does not execute any logic."""
762 test_controller.MoblabVmTest(self._Input(), self._Output(),
763 self.validate_only_config)
764 self.mock_create_moblab_vms.assert_not_called()
765
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700766 def testMockCall(self):
767 """Test mock call does not execute any logic."""
768 patch = self.PatchObject(key_value_store, 'LoadFile')
769
770 # MoblabVmTest does not return a value, checking mocked value is flagged by
771 # lint.
772 test_controller.MoblabVmTest(self._Input(), self._Output(),
773 self.mock_call_config)
774 patch.assert_not_called()
775
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600776 def testImageContainsBuilder(self):
777 """MoblabVmTest calls service with correct args."""
778 request = self._Input()
779 response = self._Output()
780
781 self.PatchObject(
Mike Frysingere652ba12019-09-08 00:57:43 -0400782 key_value_store, 'LoadFile',
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600783 return_value={cros_set_lsb_release.LSB_KEY_BUILDER_PATH: self.builder})
784
Alex Klein231d2da2019-07-22 16:44:45 -0600785 test_controller.MoblabVmTest(request, response, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600786
787 self.assertEqual(
788 self.mock_create_moblab_vms.call_args_list,
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600789 [mock.call(mock.ANY, self.chroot_dir, self.image_payload_dir)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600790 self.assertEqual(
791 self.mock_prepare_moblab_vm_image_cache.call_args_list,
792 [mock.call(mock.ANY, self.builder, [self.autotest_payload_dir])])
793 self.assertEqual(
794 self.mock_run_moblab_vm_tests.call_args_list,
Evan Hernandez655e8042019-06-13 12:50:44 -0600795 [mock.call(mock.ANY, mock.ANY, self.builder, self.image_cache_dir,
796 mock.ANY)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600797 self.assertEqual(
798 self.mock_validate_moblab_vm_tests.call_args_list,
799 [mock.call(mock.ANY)])
800
801 def testImageMissingBuilder(self):
802 """MoblabVmTest dies when builder path not found in lsb-release."""
803 request = self._Input()
804 response = self._Output()
805
Mike Frysingere652ba12019-09-08 00:57:43 -0400806 self.PatchObject(key_value_store, 'LoadFile', return_value={})
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600807
808 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600809 test_controller.MoblabVmTest(request, response, self.api_config)
David Wellingc1433c22021-06-25 16:29:48 +0000810
811
812class GetArtifactsTest(cros_test_lib.MockTempDirTestCase):
813 """Test GetArtifacts."""
814
815 CODE_COVERAGE_LLVM_ARTIFACT_TYPE = (
816 common_pb2.ArtifactsByService.Test.ArtifactType.CODE_COVERAGE_LLVM_JSON
817 )
George Engelbrecht764b1cd2021-06-18 17:01:07 -0600818 UNIT_TEST_ARTIFACT_TYPE = (
819 common_pb2.ArtifactsByService.Test.ArtifactType.UNIT_TESTS
820 )
David Wellingc1433c22021-06-25 16:29:48 +0000821
822 def setUp(self):
823 """Set up the class for tests."""
824 chroot_dir = os.path.join(self.tempdir, 'chroot')
825 osutils.SafeMakedirs(chroot_dir)
826 osutils.SafeMakedirs(os.path.join(chroot_dir, 'tmp'))
827 self.chroot = chroot_lib.Chroot(chroot_dir)
828
829 sysroot_path = os.path.join(chroot_dir, 'build', 'board')
830 osutils.SafeMakedirs(sysroot_path)
831 self.sysroot = sysroot_lib.Sysroot(sysroot_path)
832
Jack Neusc9707c32021-07-23 21:48:54 +0000833 self.build_target = build_target_lib.BuildTarget('board')
834
David Wellingc1433c22021-06-25 16:29:48 +0000835 def testReturnsEmptyListWhenNoOutputArtifactsProvided(self):
836 """Test empty list is returned when there are no output_artifacts."""
837 result = test_controller.GetArtifacts(
838 common_pb2.ArtifactsByService.Test(output_artifacts=[]),
Jack Neusc9707c32021-07-23 21:48:54 +0000839 self.chroot, self.sysroot, self.build_target, self.tempdir)
David Wellingc1433c22021-06-25 16:29:48 +0000840
841 self.assertEqual(len(result), 0)
842
843 def testShouldCallBundleCodeCoverageLlvmJsonForEachValidArtifact(self):
844 """Test BundleCodeCoverageLlvmJson is called on each valid artifact."""
Sean McAllister17eed8d2021-09-21 10:41:16 -0600845 BundleCodeCoverageLlvmJson_mock = (
846 self.PatchObject(
847 test_service,
848 'BundleCodeCoverageLlvmJson',
849 return_value='test'))
David Wellingc1433c22021-06-25 16:29:48 +0000850
851 test_controller.GetArtifacts(
852 common_pb2.ArtifactsByService.Test(output_artifacts=[
853 # Valid
854 common_pb2.ArtifactsByService.Test.ArtifactInfo(
855 artifact_types=[
856 self.CODE_COVERAGE_LLVM_ARTIFACT_TYPE
857 ]
858 ),
859
860 # Invalid
861 common_pb2.ArtifactsByService.Test.ArtifactInfo(
862 artifact_types=[
863 common_pb2.ArtifactsByService.Test.ArtifactType.UNIT_TESTS
864 ]
865 ),
866 ]),
Jack Neusc9707c32021-07-23 21:48:54 +0000867 self.chroot, self.sysroot, self.build_target, self.tempdir)
David Wellingc1433c22021-06-25 16:29:48 +0000868
869 BundleCodeCoverageLlvmJson_mock.assert_called_once()
870
871 def testShouldReturnValidResult(self):
872 """Test result contains paths and code_coverage_llvm_json type."""
873 self.PatchObject(test_service, 'BundleCodeCoverageLlvmJson',
Sean McAllister17eed8d2021-09-21 10:41:16 -0600874 return_value='test')
George Engelbrecht764b1cd2021-06-18 17:01:07 -0600875 self.PatchObject(test_service, 'BuildTargetUnitTestTarball',
Sean McAllister17eed8d2021-09-21 10:41:16 -0600876 return_value='unit_tests.tar')
David Wellingc1433c22021-06-25 16:29:48 +0000877
878 result = test_controller.GetArtifacts(
879 common_pb2.ArtifactsByService.Test(output_artifacts=[
880 # Valid
881 common_pb2.ArtifactsByService.Test.ArtifactInfo(
882 artifact_types=[
George Engelbrecht764b1cd2021-06-18 17:01:07 -0600883 self.UNIT_TEST_ARTIFACT_TYPE
884 ]
885 ),
886 common_pb2.ArtifactsByService.Test.ArtifactInfo(
887 artifact_types=[
David Wellingc1433c22021-06-25 16:29:48 +0000888 self.CODE_COVERAGE_LLVM_ARTIFACT_TYPE
889 ]
890 ),
891 ]),
Jack Neusc9707c32021-07-23 21:48:54 +0000892 self.chroot, self.sysroot, self.build_target, self.tempdir)
David Wellingc1433c22021-06-25 16:29:48 +0000893
George Engelbrecht764b1cd2021-06-18 17:01:07 -0600894 self.assertEqual(result[0]['paths'], ['unit_tests.tar'])
895 self.assertEqual(result[0]['type'], self.UNIT_TEST_ARTIFACT_TYPE)
896 self.assertEqual(result[1]['paths'], ['test'])
897 self.assertEqual(result[1]['type'], self.CODE_COVERAGE_LLVM_ARTIFACT_TYPE)