blob: 17cbf2b521b1cee5eec974b58579fd5bf9c7ba85 [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
Lizzy Presland4feb2372022-01-20 05:16:30 +00007import datetime
Mike Frysingeref94e4c2020-02-10 23:59:54 -05008import os
Mike Frysinger40443592022-05-05 13:03:40 -04009from typing import Union
Mike Frysingeref94e4c2020-02-10 23:59:54 -050010
Mike Frysinger1cc8f1f2022-04-28 22:40:40 -040011from chromite.third_party.google.protobuf import json_format
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
Lizzy Presland4feb2372022-01-20 05:16:30 +000015from chromite.api.controller import controller_util
Alex Kleina2e42c42019-04-17 16:13:19 -060016from chromite.api.controller import test as test_controller
17from chromite.api.gen.chromite.api import test_pb2
Mike Frysinger1cc8f1f2022-04-28 22:40:40 -040018from chromite.api.gen.chromiumos import common_pb2
Sean McAllister3834fef2021-10-08 15:45:18 -060019from chromite.api.gen.chromiumos.build.api import container_metadata_pb2
Jack Neusc9707c32021-07-23 21:48:54 +000020from chromite.lib import build_target_lib
Evan Hernandeze1e05d32019-07-19 12:32:18 -060021from chromite.lib import chroot_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060022from chromite.lib import cros_build_lib
23from chromite.lib import cros_test_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060024from chromite.lib import osutils
David Wellingc1433c22021-06-25 16:29:48 +000025from chromite.lib import sysroot_lib
Alex Klein18a60af2020-06-11 12:08:47 -060026from chromite.lib.parser import package_info
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060027from chromite.service import test as test_service
Alex Kleina2e42c42019-04-17 16:13:19 -060028
29
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -070030class DebugInfoTestTest(cros_test_lib.MockTempDirTestCase,
31 api_config.ApiConfigMixin):
32 """Tests for the DebugInfoTest function."""
33
34 def setUp(self):
35 self.board = 'board'
36 self.chroot_path = os.path.join(self.tempdir, 'chroot')
37 self.sysroot_path = '/build/board'
38 self.full_sysroot_path = os.path.join(self.chroot_path,
39 self.sysroot_path.lstrip(os.sep))
40 osutils.SafeMakedirs(self.full_sysroot_path)
41
42 def _GetInput(self, sysroot_path=None, build_target=None):
43 """Helper to build an input message instance."""
44 proto = test_pb2.DebugInfoTestRequest()
45 if sysroot_path:
46 proto.sysroot.path = sysroot_path
47 if build_target:
48 proto.sysroot.build_target.name = build_target
49 return proto
50
51 def _GetOutput(self):
52 """Helper to get an empty output message instance."""
53 return test_pb2.DebugInfoTestResponse()
54
55 def testValidateOnly(self):
56 """Sanity check that a validate only call does not execute any logic."""
57 patch = self.PatchObject(test_service, 'DebugInfoTest')
58 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
59 test_controller.DebugInfoTest(input_msg, self._GetOutput(),
60 self.validate_only_config)
61 patch.assert_not_called()
62
Michael Mortensen85d38402019-12-12 09:50:29 -070063 def testMockError(self):
64 """Test mock error call does not execute any logic, returns error."""
65 patch = self.PatchObject(test_service, 'DebugInfoTest')
66
67 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
68 rc = test_controller.DebugInfoTest(input_msg, self._GetOutput(),
69 self.mock_error_config)
70 patch.assert_not_called()
71 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
72
73 def testMockCall(self):
74 """Test mock call does not execute any logic, returns success."""
75 patch = self.PatchObject(test_service, 'DebugInfoTest')
76
77 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
78 rc = test_controller.DebugInfoTest(input_msg, self._GetOutput(),
79 self.mock_call_config)
80 patch.assert_not_called()
81 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
82
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -070083 def testNoBuildTargetNoSysrootFails(self):
84 """Test missing build target name and sysroot path fails."""
85 input_msg = self._GetInput()
86 output_msg = self._GetOutput()
87 with self.assertRaises(cros_build_lib.DieSystemExit):
88 test_controller.DebugInfoTest(input_msg, output_msg, self.api_config)
89
90 def testDebugInfoTest(self):
91 """Call DebugInfoTest with valid sysroot_path."""
92 request = self._GetInput(sysroot_path=self.full_sysroot_path)
93
94 test_controller.DebugInfoTest(request, self._GetOutput(), self.api_config)
95
96
Alex Klein231d2da2019-07-22 16:44:45 -060097class BuildTargetUnitTestTest(cros_test_lib.MockTempDirTestCase,
98 api_config.ApiConfigMixin):
Alex Kleina2e42c42019-04-17 16:13:19 -060099 """Tests for the UnitTest function."""
100
Lizzy Presland4feb2372022-01-20 05:16:30 +0000101 def setUp(self):
102 # Set up portage log directory.
103 self.sysroot = os.path.join(self.tempdir, 'build', 'board')
104 osutils.SafeMakedirs(self.sysroot)
105 self.target_sysroot = sysroot_lib.Sysroot(self.sysroot)
106 self.portage_dir = os.path.join(self.tempdir, 'portage_logdir')
107 self.PatchObject(
108 sysroot_lib.Sysroot, 'portage_logdir', new=self.portage_dir)
109 osutils.SafeMakedirs(self.portage_dir)
110
Navil Perezc0b29a82020-07-07 14:17:48 +0000111 def _GetInput(self,
112 board=None,
Navil Perezc0b29a82020-07-07 14:17:48 +0000113 chroot_path=None,
114 cache_dir=None,
115 empty_sysroot=None,
116 packages=None,
Alex Kleinb64e5f82020-09-23 10:55:31 -0600117 blocklist=None):
Alex Kleina2e42c42019-04-17 16:13:19 -0600118 """Helper to build an input message instance."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000119 formatted_packages = []
120 for pkg in packages or []:
121 formatted_packages.append({
122 'category': pkg.category,
123 'package_name': pkg.package
124 })
Alex Kleinb64e5f82020-09-23 10:55:31 -0600125 formatted_blocklist = []
126 for pkg in blocklist or []:
Alex Klein4f215432022-05-23 10:41:14 -0600127 formatted_blocklist.append({
128 'category': pkg.category,
129 'package_name': pkg.package
130 })
Alex Kleinf2674462019-05-16 16:47:24 -0600131
Alex Kleina2e42c42019-04-17 16:13:19 -0600132 return test_pb2.BuildTargetUnitTestRequest(
Alex Klein4f215432022-05-23 10:41:14 -0600133 build_target={'name': board},
Alex Klein4f215432022-05-23 10:41:14 -0600134 chroot={
135 'path': chroot_path,
136 'cache_dir': cache_dir
137 },
Alex Kleinf2674462019-05-16 16:47:24 -0600138 flags={'empty_sysroot': empty_sysroot},
Alex Klein64ac34c2020-09-23 10:21:33 -0600139 packages=formatted_packages,
Alex Klein157caf42021-07-01 14:36:43 -0600140 package_blocklist=formatted_blocklist,
Alex Kleina2e42c42019-04-17 16:13:19 -0600141 )
142
143 def _GetOutput(self):
144 """Helper to get an empty output message instance."""
145 return test_pb2.BuildTargetUnitTestResponse()
146
Alex Klein4f215432022-05-23 10:41:14 -0600147 def _CreatePortageLogFile(self, log_path: Union[str, os.PathLike],
Mike Frysinger40443592022-05-05 13:03:40 -0400148 pkg_info: package_info.PackageInfo,
149 timestamp: datetime.datetime) -> str:
Lizzy Presland4feb2372022-01-20 05:16:30 +0000150 """Creates a log file for testing for individual packages built by Portage.
151
152 Args:
Mike Frysinger40443592022-05-05 13:03:40 -0400153 log_path: The PORTAGE_LOGDIR path.
154 pkg_info: name components for log file.
155 timestamp: Timestamp used to name the file.
Lizzy Presland4feb2372022-01-20 05:16:30 +0000156 """
157 path = os.path.join(log_path,
158 f'{pkg_info.category}:{pkg_info.pvr}:' \
159 f'{timestamp.strftime("%Y%m%d-%H%M%S")}.log')
Alex Klein4f215432022-05-23 10:41:14 -0600160 osutils.WriteFile(
161 path, f'Test log file for package {pkg_info.category}/'
162 f'{pkg_info.package} written to {path}')
Lizzy Presland4feb2372022-01-20 05:16:30 +0000163 return path
164
Alex Klein231d2da2019-07-22 16:44:45 -0600165 def testValidateOnly(self):
166 """Sanity check that a validate only call does not execute any logic."""
167 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
168
Alex Klein0aecf472022-05-23 10:48:45 -0600169 input_msg = self._GetInput(board='board')
Alex Klein231d2da2019-07-22 16:44:45 -0600170 test_controller.BuildTargetUnitTest(input_msg, self._GetOutput(),
171 self.validate_only_config)
172 patch.assert_not_called()
173
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700174 def testMockCall(self):
175 """Test that a mock call does not execute logic, returns mocked value."""
176 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
177
Alex Klein0aecf472022-05-23 10:48:45 -0600178 input_msg = self._GetInput(board='board')
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700179 response = self._GetOutput()
180 test_controller.BuildTargetUnitTest(input_msg, response,
181 self.mock_call_config)
182 patch.assert_not_called()
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700183
184 def testMockError(self):
Michael Mortensen85d38402019-12-12 09:50:29 -0700185 """Test that a mock error does not execute logic, returns error."""
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700186 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
187
Alex Klein0aecf472022-05-23 10:48:45 -0600188 input_msg = self._GetInput(board='board')
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700189 response = self._GetOutput()
190 rc = test_controller.BuildTargetUnitTest(input_msg, response,
191 self.mock_error_config)
192 patch.assert_not_called()
193 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000194 self.assertTrue(response.failed_package_data)
195 self.assertEqual(response.failed_package_data[0].name.category, 'foo')
196 self.assertEqual(response.failed_package_data[0].name.package_name, 'bar')
197 self.assertEqual(response.failed_package_data[1].name.category, 'cat')
198 self.assertEqual(response.failed_package_data[1].name.package_name, 'pkg')
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700199
Alex Klein64ac34c2020-09-23 10:21:33 -0600200 def testInvalidPackageFails(self):
201 """Test missing result path fails."""
202 # Missing result_path.
203 pkg = package_info.PackageInfo(package='bar')
Alex Klein0aecf472022-05-23 10:48:45 -0600204 input_msg = self._GetInput(board='board', packages=[pkg])
Alex Klein64ac34c2020-09-23 10:21:33 -0600205 output_msg = self._GetOutput()
206 with self.assertRaises(cros_build_lib.DieSystemExit):
207 test_controller.BuildTargetUnitTest(input_msg, output_msg,
208 self.api_config)
209
Alex Kleina2e42c42019-04-17 16:13:19 -0600210 def testPackageBuildFailure(self):
211 """Test handling of raised BuildPackageFailure."""
212 tempdir = osutils.TempDir(base_dir=self.tempdir)
213 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
214
Lizzy Presland4feb2372022-01-20 05:16:30 +0000215 pkgs = ['cat/pkg-1.0-r1', 'foo/bar-2.0-r1']
216 cpvrs = [package_info.parse(pkg) for pkg in pkgs]
Alex Kleina2e42c42019-04-17 16:13:19 -0600217 expected = [('cat', 'pkg'), ('foo', 'bar')]
Lizzy Presland4feb2372022-01-20 05:16:30 +0000218 new_logs = {}
219 for i, pkg in enumerate(pkgs):
220 self._CreatePortageLogFile(self.portage_dir, cpvrs[i],
221 datetime.datetime(2021, 6, 9, 13, 37, 0))
Alex Klein4f215432022-05-23 10:41:14 -0600222 new_logs[pkg] = self._CreatePortageLogFile(
223 self.portage_dir, cpvrs[i], datetime.datetime(2021, 6, 9, 16, 20, 0))
Alex Kleina2e42c42019-04-17 16:13:19 -0600224
Alex Klein38c7d9e2019-05-08 09:31:19 -0600225 result = test_service.BuildTargetUnitTestResult(1, None)
Alex Kleinea0c89e2021-09-09 15:17:35 -0600226 result.failed_pkgs = [package_info.parse(p) for p in pkgs]
Alex Klein38c7d9e2019-05-08 09:31:19 -0600227 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600228
Alex Klein0aecf472022-05-23 10:48:45 -0600229 input_msg = self._GetInput(board='board')
Alex Kleina2e42c42019-04-17 16:13:19 -0600230 output_msg = self._GetOutput()
231
Alex Klein231d2da2019-07-22 16:44:45 -0600232 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
233 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600234
Alex Klein8cb365a2019-05-15 16:24:53 -0600235 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Lizzy Presland4feb2372022-01-20 05:16:30 +0000236 self.assertTrue(output_msg.failed_package_data)
Alex Kleina2e42c42019-04-17 16:13:19 -0600237
Lizzy Presland4feb2372022-01-20 05:16:30 +0000238 failed_with_logs = []
239 for data in output_msg.failed_package_data:
240 failed_with_logs.append((data.name.category, data.name.package_name))
241 package = controller_util.deserialize_package_info(data.name)
242 self.assertEqual(data.log_path.path, new_logs[package.cpvr])
243 self.assertCountEqual(expected, failed_with_logs)
244
Alex Kleina2e42c42019-04-17 16:13:19 -0600245 def testOtherBuildScriptFailure(self):
246 """Test build script failure due to non-package emerge error."""
247 tempdir = osutils.TempDir(base_dir=self.tempdir)
248 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
249
Alex Klein38c7d9e2019-05-08 09:31:19 -0600250 result = test_service.BuildTargetUnitTestResult(1, None)
251 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600252
Alex Kleinf2674462019-05-16 16:47:24 -0600253 pkgs = ['foo/bar', 'cat/pkg']
Alex Kleinb64e5f82020-09-23 10:55:31 -0600254 blocklist = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Klein4f215432022-05-23 10:41:14 -0600255 input_msg = self._GetInput(
256 board='board', empty_sysroot=True, blocklist=blocklist)
Alex Kleina2e42c42019-04-17 16:13:19 -0600257 output_msg = self._GetOutput()
258
Alex Klein231d2da2019-07-22 16:44:45 -0600259 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
260 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600261
Alex Klein8cb365a2019-05-15 16:24:53 -0600262 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
Lizzy Presland239459a2022-05-05 22:03:19 +0000263 self.assertFalse(output_msg.failed_package_data)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600264
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700265 def testBuildTargetUnitTest(self):
266 """Test BuildTargetUnitTest successful call."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000267 pkgs = ['foo/bar', 'cat/pkg']
Alex Klein18a60af2020-06-11 12:08:47 -0600268 packages = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Klein2e91e522022-01-14 09:22:03 -0700269 input_msg = self._GetInput(board='board', packages=packages)
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700270
271 result = test_service.BuildTargetUnitTestResult(0, None)
272 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
273
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700274 response = self._GetOutput()
Alex Klein4f215432022-05-23 10:41:14 -0600275 test_controller.BuildTargetUnitTest(input_msg, response, self.api_config)
Lizzy Presland239459a2022-05-05 22:03:19 +0000276 self.assertFalse(response.failed_package_data)
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700277
Evan Hernandez4e388a52019-05-01 12:16:33 -0600278
Sean McAllister17eed8d2021-09-21 10:41:16 -0600279class DockerConstraintsTest(cros_test_lib.MockTestCase):
280 """Tests for Docker argument constraints."""
281
282 def assertValid(self, output):
283 return output is None
284
285 def assertInvalid(self, output):
286 return not self.assertValid(output)
287
288 def testValidDockerTag(self):
289 """Check logic for validating docker tag format."""
290 # pylint: disable=protected-access
291
292 invalid_tags = [
293 '.invalid-tag',
294 '-invalid-tag',
295 'invalid-tag;',
Alex Klein4f215432022-05-23 10:41:14 -0600296 'invalid' * 100,
Sean McAllister17eed8d2021-09-21 10:41:16 -0600297 ]
298
299 for tag in invalid_tags:
300 self.assertInvalid(test_controller._ValidDockerTag(tag))
301
302 valid_tags = [
303 'valid-tag',
304 'valid-tag-',
305 'valid.tag.',
306 ]
307
308 for tag in valid_tags:
309 self.assertValid(test_controller._ValidDockerTag(tag))
310
Sean McAllister17eed8d2021-09-21 10:41:16 -0600311 def testValidDockerLabelKey(self):
312 """Check logic for validating docker label key format."""
313 # pylint: disable=protected-access
314
315 invalid_keys = [
316 'Invalid-keY',
317 'Invalid-key',
318 'invalid-keY',
319 'iNVALID-KEy',
320 'invalid_key',
321 'invalid-key;',
322 ]
323
324 for key in invalid_keys:
325 self.assertInvalid(test_controller._ValidDockerLabelKey(key))
326
327 valid_keys = [
328 'chromeos.valid-key',
329 'chromeos.valid-key-2',
330 ]
331
332 for key in valid_keys:
333 self.assertValid(test_controller._ValidDockerLabelKey(key))
334
335
Sean McAllister3834fef2021-10-08 15:45:18 -0600336class BuildTestServiceContainers(cros_test_lib.RunCommandTempDirTestCase,
David Wellingc1433c22021-06-25 16:29:48 +0000337 api_config.ApiConfigMixin):
C Shapiro91af1ce2021-06-17 12:42:09 -0500338 """Tests for the BuildTestServiceContainers function."""
339
340 def setUp(self):
341 self.request = test_pb2.BuildTestServiceContainersRequest(
342 chroot={'path': '/path/to/chroot'},
343 build_target={'name': 'build_target'},
David Wellingc1433c22021-06-25 16:29:48 +0000344 version='R93-14033.0.0',
C Shapiro91af1ce2021-06-17 12:42:09 -0500345 )
346
C Shapiro91af1ce2021-06-17 12:42:09 -0500347 def testSuccess(self):
348 """Check passing case with mocked cros_build_lib.run."""
Sean McAllister3834fef2021-10-08 15:45:18 -0600349
350 def ContainerMetadata():
351 """Return mocked ContainerImageInfo proto"""
352 metadata = container_metadata_pb2.ContainerImageInfo()
353 metadata.repository.hostname = 'gcr.io'
354 metadata.repository.project = 'chromeos-bot'
355 metadata.name = 'random-container-name'
356 metadata.digest = (
357 '09b730f8b6a862f9c2705cb3acf3554563325f5fca5c784bf5c98beb2e56f6db')
358 metadata.tags[:] = [
359 'staging-cq-amd64-generic.R96-1.2.3',
360 '8834106026340379089',
361 ]
362 return metadata
363
364 def WriteContainerMetadata(path):
365 """Write json formatted metadata to the given file."""
366 osutils.WriteFile(
367 path,
368 json_format.MessageToJson(ContainerMetadata()),
369 )
370
371 # Write out mocked container metadata to a temporary file.
372 output_path = os.path.join(self.tempdir, 'metadata.jsonpb')
373 self.rc.SetDefaultCmdResult(
374 returncode=0,
Alex Klein4f215432022-05-23 10:41:14 -0600375 side_effect=lambda *_, **__: WriteContainerMetadata(output_path))
Sean McAllister3834fef2021-10-08 15:45:18 -0600376
377 # Patch TempDir so that we always use this test's directory.
378 self.PatchObject(osutils.TempDir, '__enter__', return_value=self.tempdir)
C Shapiro91af1ce2021-06-17 12:42:09 -0500379
380 response = test_pb2.BuildTestServiceContainersResponse()
Alex Klein4f215432022-05-23 10:41:14 -0600381 test_controller.BuildTestServiceContainers(self.request, response,
382 self.api_config)
Sean McAllister3834fef2021-10-08 15:45:18 -0600383
384 self.assertTrue(self.rc.called)
C Shapiro91af1ce2021-06-17 12:42:09 -0500385 for result in response.results:
386 self.assertEqual(result.WhichOneof('result'), 'success')
Sean McAllister3834fef2021-10-08 15:45:18 -0600387 self.assertEqual(result.success.image_info, ContainerMetadata())
C Shapiro91af1ce2021-06-17 12:42:09 -0500388
C Shapiro91af1ce2021-06-17 12:42:09 -0500389 def testFailure(self):
390 """Check failure case with mocked cros_build_lib.run."""
391 patch = self.PatchObject(
Alex Klein4f215432022-05-23 10:41:14 -0600392 cros_build_lib,
393 'run',
Mike Frysinger112b67c2022-08-08 00:52:10 -0400394 return_value=cros_build_lib.CompletedProcess(returncode=1))
C Shapiro91af1ce2021-06-17 12:42:09 -0500395
396 response = test_pb2.BuildTestServiceContainersResponse()
Alex Klein4f215432022-05-23 10:41:14 -0600397 test_controller.BuildTestServiceContainers(self.request, response,
398 self.api_config)
C Shapiro91af1ce2021-06-17 12:42:09 -0500399 patch.assert_called()
400 for result in response.results:
Derek Beckett27eaa162022-05-09 10:42:53 -0700401 self.assertEqual(result.WhichOneof('result'), 'failure')
Derek Beckett344b5a82022-05-09 17:21:45 -0700402 self.assertEqual(result.name, 'Service Builder')
C Shapiro91af1ce2021-06-17 12:42:09 -0500403
Alex Klein4f215432022-05-23 10:41:14 -0600404
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700405class ChromiteUnitTestTest(cros_test_lib.MockTestCase,
406 api_config.ApiConfigMixin):
407 """Tests for the ChromiteInfoTest function."""
408
409 def setUp(self):
410 self.board = 'board'
411 self.chroot_path = '/path/to/chroot'
412
413 def _GetInput(self, chroot_path=None):
414 """Helper to build an input message instance."""
Alex Klein4f215432022-05-23 10:41:14 -0600415 proto = test_pb2.ChromiteUnitTestRequest(chroot={'path': chroot_path},)
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700416 return proto
417
418 def _GetOutput(self):
419 """Helper to get an empty output message instance."""
420 return test_pb2.ChromiteUnitTestResponse()
421
422 def testValidateOnly(self):
423 """Sanity check that a validate only call does not execute any logic."""
424 patch = self.PatchObject(cros_build_lib, 'run')
425
426 input_msg = self._GetInput(chroot_path=self.chroot_path)
427 test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
428 self.validate_only_config)
429 patch.assert_not_called()
430
Michael Mortensen7a860eb2019-12-03 20:25:15 -0700431 def testMockError(self):
432 """Test mock error call does not execute any logic, returns error."""
433 patch = self.PatchObject(cros_build_lib, 'run')
434
435 input_msg = self._GetInput(chroot_path=self.chroot_path)
436 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
437 self.mock_error_config)
438 patch.assert_not_called()
439 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
440
441 def testMockCall(self):
442 """Test mock call does not execute any logic, returns success."""
443 patch = self.PatchObject(cros_build_lib, 'run')
444
445 input_msg = self._GetInput(chroot_path=self.chroot_path)
446 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
447 self.mock_call_config)
448 patch.assert_not_called()
449 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
450
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700451 def testChromiteUnitTest(self):
452 """Call ChromiteUnitTest with mocked cros_build_lib.run."""
453 request = self._GetInput(chroot_path=self.chroot_path)
454 patch = self.PatchObject(
Alex Klein4f215432022-05-23 10:41:14 -0600455 cros_build_lib,
456 'run',
Mike Frysinger112b67c2022-08-08 00:52:10 -0400457 return_value=cros_build_lib.CompletedProcess(returncode=0))
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700458
459 test_controller.ChromiteUnitTest(request, self._GetOutput(),
460 self.api_config)
461 patch.assert_called_once()
462
463
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600464class CrosSigningTestTest(cros_test_lib.RunCommandTestCase,
465 api_config.ApiConfigMixin):
466 """CrosSigningTest tests."""
467
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700468 def setUp(self):
469 self.chroot_path = '/path/to/chroot'
470
471 def _GetInput(self, chroot_path=None):
472 """Helper to build an input message instance."""
Alex Klein4f215432022-05-23 10:41:14 -0600473 proto = test_pb2.CrosSigningTestRequest(chroot={'path': chroot_path},)
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700474 return proto
475
476 def _GetOutput(self):
477 """Helper to get an empty output message instance."""
478 return test_pb2.CrosSigningTestResponse()
479
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600480 def testValidateOnly(self):
481 """Sanity check that a validate only call does not execute any logic."""
482 test_controller.CrosSigningTest(None, None, self.validate_only_config)
483 self.assertFalse(self.rc.call_count)
484
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700485 def testMockCall(self):
486 """Test mock call does not execute any logic, returns success."""
487 rc = test_controller.CrosSigningTest(None, None, self.mock_call_config)
488 self.assertFalse(self.rc.call_count)
489 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
490
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700491 def testCrosSigningTest(self):
492 """Call CrosSigningTest with mocked cros_build_lib.run."""
493 request = self._GetInput(chroot_path=self.chroot_path)
494 patch = self.PatchObject(
Alex Klein4f215432022-05-23 10:41:14 -0600495 cros_build_lib,
496 'run',
Mike Frysinger112b67c2022-08-08 00:52:10 -0400497 return_value=cros_build_lib.CompletedProcess(returncode=0))
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700498
Alex Klein4f215432022-05-23 10:41:14 -0600499 test_controller.CrosSigningTest(request, self._GetOutput(), self.api_config)
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700500 patch.assert_called_once()
501
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600502
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600503class SimpleChromeWorkflowTestTest(cros_test_lib.MockTestCase,
504 api_config.ApiConfigMixin):
505 """Test the SimpleChromeWorkflowTest endpoint."""
506
507 @staticmethod
508 def _Output():
509 return test_pb2.SimpleChromeWorkflowTestResponse()
510
David Wellingc1433c22021-06-25 16:29:48 +0000511 def _Input(self,
512 sysroot_path=None,
513 build_target=None,
514 chrome_root=None,
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600515 goma_config=None):
516 proto = test_pb2.SimpleChromeWorkflowTestRequest()
517 if sysroot_path:
518 proto.sysroot.path = sysroot_path
519 if build_target:
520 proto.sysroot.build_target.name = build_target
521 if chrome_root:
522 proto.chrome_root = chrome_root
523 if goma_config:
524 proto.goma_config = goma_config
525 return proto
526
527 def setUp(self):
528 self.chrome_path = 'path/to/chrome'
529 self.sysroot_dir = 'build/board'
530 self.build_target = 'amd64'
531 self.mock_simple_chrome_workflow_test = self.PatchObject(
532 test_service, 'SimpleChromeWorkflowTest')
533
534 def testMissingBuildTarget(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700535 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Alex Klein4f215432022-05-23 10:41:14 -0600536 input_proto = self._Input(
537 build_target=None,
538 sysroot_path='/sysroot/dir',
539 chrome_root='/chrome/path')
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600540 with self.assertRaises(cros_build_lib.DieSystemExit):
541 test_controller.SimpleChromeWorkflowTest(input_proto, None,
542 self.api_config)
543
544 def testMissingSysrootPath(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700545 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Alex Klein4f215432022-05-23 10:41:14 -0600546 input_proto = self._Input(
547 build_target='board', sysroot_path=None, chrome_root='/chrome/path')
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600548 with self.assertRaises(cros_build_lib.DieSystemExit):
549 test_controller.SimpleChromeWorkflowTest(input_proto, None,
550 self.api_config)
551
552 def testMissingChromeRoot(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700553 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Alex Klein4f215432022-05-23 10:41:14 -0600554 input_proto = self._Input(
555 build_target='board', sysroot_path='/sysroot/dir', chrome_root=None)
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600556 with self.assertRaises(cros_build_lib.DieSystemExit):
557 test_controller.SimpleChromeWorkflowTest(input_proto, None,
558 self.api_config)
559
560 def testSimpleChromeWorkflowTest(self):
561 """Call SimpleChromeWorkflowTest with valid args and temp dir."""
Alex Klein4f215432022-05-23 10:41:14 -0600562 request = self._Input(
563 sysroot_path='sysroot_path',
564 build_target='board',
565 chrome_root='/path/to/chrome')
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600566 response = self._Output()
567
568 test_controller.SimpleChromeWorkflowTest(request, response, self.api_config)
569 self.mock_simple_chrome_workflow_test.assert_called()
570
571 def testValidateOnly(self):
Alex Klein4f215432022-05-23 10:41:14 -0600572 request = self._Input(
573 sysroot_path='sysroot_path',
574 build_target='board',
575 chrome_root='/path/to/chrome')
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600576 test_controller.SimpleChromeWorkflowTest(request, self._Output(),
577 self.validate_only_config)
578 self.mock_simple_chrome_workflow_test.assert_not_called()
579
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700580 def testMockCall(self):
581 """Test mock call does not execute any logic, returns success."""
582 patch = self.mock_simple_chrome_workflow_test = self.PatchObject(
583 test_service, 'SimpleChromeWorkflowTest')
584
Alex Klein4f215432022-05-23 10:41:14 -0600585 request = self._Input(
586 sysroot_path='sysroot_path',
587 build_target='board',
588 chrome_root='/path/to/chrome')
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700589 rc = test_controller.SimpleChromeWorkflowTest(request, self._Output(),
590 self.mock_call_config)
591 patch.assert_not_called()
592 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
593
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600594
Alex Klein231d2da2019-07-22 16:44:45 -0600595class VmTestTest(cros_test_lib.RunCommandTestCase, api_config.ApiConfigMixin):
Evan Hernandez4e388a52019-05-01 12:16:33 -0600596 """Test the VmTest endpoint."""
597
598 def _GetInput(self, **kwargs):
599 values = dict(
600 build_target=common_pb2.BuildTarget(name='target'),
Alex Klein4f215432022-05-23 10:41:14 -0600601 vm_path=common_pb2.Path(
602 path='/path/to/image.bin', location=common_pb2.Path.INSIDE),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600603 test_harness=test_pb2.VmTestRequest.TAST,
604 vm_tests=[test_pb2.VmTestRequest.VmTest(pattern='suite')],
605 ssh_options=test_pb2.VmTestRequest.SshOptions(
Alex Klein4f215432022-05-23 10:41:14 -0600606 port=1234,
607 private_key_path={
608 'path': '/path/to/id_rsa',
609 'location': common_pb2.Path.INSIDE
610 }),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600611 )
612 values.update(kwargs)
613 return test_pb2.VmTestRequest(**values)
614
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700615 def _Output(self):
616 return test_pb2.VmTestResponse()
617
Alex Klein231d2da2019-07-22 16:44:45 -0600618 def testValidateOnly(self):
619 """Sanity check that a validate only call does not execute any logic."""
620 test_controller.VmTest(self._GetInput(), None, self.validate_only_config)
621 self.assertEqual(0, self.rc.call_count)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600622
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700623 def testMockCall(self):
624 """Test mock call does not execute any logic."""
625 patch = self.PatchObject(cros_build_lib, 'run')
626
627 request = self._GetInput()
628 response = self._Output()
629 # VmTest does not return a value, checking mocked value is flagged by lint.
630 test_controller.VmTest(request, response, self.mock_call_config)
631 patch.assert_not_called()
632
Evan Hernandez4e388a52019-05-01 12:16:33 -0600633 def testTastAllOptions(self):
634 """Test VmTest for Tast with all options set."""
Alex Klein231d2da2019-07-22 16:44:45 -0600635 test_controller.VmTest(self._GetInput(), None, self.api_config)
636 self.assertCommandContains([
Alex Klein4f215432022-05-23 10:41:14 -0600637 'cros_run_test',
638 '--debug',
639 '--no-display',
640 '--copy-on-write',
641 '--board',
642 'target',
643 '--image-path',
644 '/path/to/image.bin',
645 '--tast',
646 'suite',
647 '--ssh-port',
648 '1234',
649 '--private-key',
650 '/path/to/id_rsa',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600651 ])
652
653 def testAutotestAllOptions(self):
654 """Test VmTest for Autotest with all options set."""
655 input_proto = self._GetInput(test_harness=test_pb2.VmTestRequest.AUTOTEST)
Alex Klein231d2da2019-07-22 16:44:45 -0600656 test_controller.VmTest(input_proto, None, self.api_config)
657 self.assertCommandContains([
Alex Klein4f215432022-05-23 10:41:14 -0600658 'cros_run_test',
659 '--debug',
660 '--no-display',
661 '--copy-on-write',
662 '--board',
663 'target',
664 '--image-path',
665 '/path/to/image.bin',
666 '--autotest',
667 'suite',
668 '--ssh-port',
669 '1234',
670 '--private-key',
671 '/path/to/id_rsa',
Greg Edelstondcb0e912020-08-31 11:09:40 -0600672 '--test_that-args=--allow-chrome-crashes',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600673 ])
674
675 def testMissingBuildTarget(self):
676 """Test VmTest dies when build_target not set."""
677 input_proto = self._GetInput(build_target=None)
678 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600679 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600680
681 def testMissingVmImage(self):
682 """Test VmTest dies when vm_image not set."""
Alex Klein311b8022019-06-05 16:00:07 -0600683 input_proto = self._GetInput(vm_path=None)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600684 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600685 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600686
687 def testMissingTestHarness(self):
688 """Test VmTest dies when test_harness not specified."""
689 input_proto = self._GetInput(
690 test_harness=test_pb2.VmTestRequest.UNSPECIFIED)
691 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600692 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600693
694 def testMissingVmTests(self):
695 """Test VmTest dies when vm_tests not set."""
696 input_proto = self._GetInput(vm_tests=[])
697 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600698 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600699
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700700 def testVmTest(self):
701 """Call VmTest with valid args and temp dir."""
702 request = self._GetInput()
703 response = self._Output()
704 patch = self.PatchObject(
Alex Klein4f215432022-05-23 10:41:14 -0600705 cros_build_lib,
706 'run',
Mike Frysinger112b67c2022-08-08 00:52:10 -0400707 return_value=cros_build_lib.CompletedProcess(returncode=0))
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700708
709 test_controller.VmTest(request, response, self.api_config)
710 patch.assert_called()
711
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600712
David Wellingc1433c22021-06-25 16:29:48 +0000713class GetArtifactsTest(cros_test_lib.MockTempDirTestCase):
714 """Test GetArtifacts."""
715
716 CODE_COVERAGE_LLVM_ARTIFACT_TYPE = (
Alex Klein4f215432022-05-23 10:41:14 -0600717 common_pb2.ArtifactsByService.Test.ArtifactType.CODE_COVERAGE_LLVM_JSON)
David Wellingc1433c22021-06-25 16:29:48 +0000718
719 def setUp(self):
720 """Set up the class for tests."""
721 chroot_dir = os.path.join(self.tempdir, 'chroot')
722 osutils.SafeMakedirs(chroot_dir)
723 osutils.SafeMakedirs(os.path.join(chroot_dir, 'tmp'))
724 self.chroot = chroot_lib.Chroot(chroot_dir)
725
726 sysroot_path = os.path.join(chroot_dir, 'build', 'board')
727 osutils.SafeMakedirs(sysroot_path)
728 self.sysroot = sysroot_lib.Sysroot(sysroot_path)
729
Jack Neusc9707c32021-07-23 21:48:54 +0000730 self.build_target = build_target_lib.BuildTarget('board')
731
David Wellingc1433c22021-06-25 16:29:48 +0000732 def testReturnsEmptyListWhenNoOutputArtifactsProvided(self):
733 """Test empty list is returned when there are no output_artifacts."""
734 result = test_controller.GetArtifacts(
Alex Klein4f215432022-05-23 10:41:14 -0600735 common_pb2.ArtifactsByService.Test(output_artifacts=[]), self.chroot,
736 self.sysroot, self.build_target, self.tempdir)
David Wellingc1433c22021-06-25 16:29:48 +0000737
738 self.assertEqual(len(result), 0)
739
740 def testShouldCallBundleCodeCoverageLlvmJsonForEachValidArtifact(self):
741 """Test BundleCodeCoverageLlvmJson is called on each valid artifact."""
Sean McAllister17eed8d2021-09-21 10:41:16 -0600742 BundleCodeCoverageLlvmJson_mock = (
743 self.PatchObject(
Alex Klein4f215432022-05-23 10:41:14 -0600744 test_service, 'BundleCodeCoverageLlvmJson', return_value='test'))
David Wellingc1433c22021-06-25 16:29:48 +0000745
746 test_controller.GetArtifacts(
747 common_pb2.ArtifactsByService.Test(output_artifacts=[
748 # Valid
749 common_pb2.ArtifactsByService.Test.ArtifactInfo(
Alex Klein4f215432022-05-23 10:41:14 -0600750 artifact_types=[self.CODE_COVERAGE_LLVM_ARTIFACT_TYPE]),
David Wellingc1433c22021-06-25 16:29:48 +0000751
752 # Invalid
Alex Klein4f215432022-05-23 10:41:14 -0600753 common_pb2.ArtifactsByService.Test.ArtifactInfo(artifact_types=[
754 common_pb2.ArtifactsByService.Test.ArtifactType.UNIT_TESTS
755 ]),
David Wellingc1433c22021-06-25 16:29:48 +0000756 ]),
Alex Klein4f215432022-05-23 10:41:14 -0600757 self.chroot,
758 self.sysroot,
759 self.build_target,
760 self.tempdir)
David Wellingc1433c22021-06-25 16:29:48 +0000761
762 BundleCodeCoverageLlvmJson_mock.assert_called_once()
763
764 def testShouldReturnValidResult(self):
765 """Test result contains paths and code_coverage_llvm_json type."""
Alex Klein4f215432022-05-23 10:41:14 -0600766 self.PatchObject(
767 test_service, 'BundleCodeCoverageLlvmJson', return_value='test')
David Wellingc1433c22021-06-25 16:29:48 +0000768
769 result = test_controller.GetArtifacts(
770 common_pb2.ArtifactsByService.Test(output_artifacts=[
771 # Valid
772 common_pb2.ArtifactsByService.Test.ArtifactInfo(
Alex Klein4f215432022-05-23 10:41:14 -0600773 artifact_types=[self.CODE_COVERAGE_LLVM_ARTIFACT_TYPE]),
David Wellingc1433c22021-06-25 16:29:48 +0000774 ]),
Alex Klein4f215432022-05-23 10:41:14 -0600775 self.chroot,
776 self.sysroot,
777 self.build_target,
778 self.tempdir)
David Wellingc1433c22021-06-25 16:29:48 +0000779
Alex Klein6e7e4c22022-01-14 09:26:05 -0700780 self.assertEqual(result[0]['paths'], ['test'])
781 self.assertEqual(result[0]['type'], self.CODE_COVERAGE_LLVM_ARTIFACT_TYPE)