blob: 64742ca6a8fa1094eb0b57cf0a7fdd246b7788a1 [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
Mike Frysingeref94e4c2020-02-10 23:59:54 -05008import os
Mike Frysinger166fea02021-02-12 05:30:33 -05009from unittest import mock
Mike Frysingeref94e4c2020-02-10 23:59:54 -050010
Alex Klein231d2da2019-07-22 16:44:45 -060011from chromite.api import api_config
Alex Klein8cb365a2019-05-15 16:24:53 -060012from chromite.api import controller
Alex Kleina2e42c42019-04-17 16:13:19 -060013from chromite.api.controller import test as test_controller
Evan Hernandez4e388a52019-05-01 12:16:33 -060014from chromite.api.gen.chromiumos import common_pb2
Alex Kleina2e42c42019-04-17 16:13:19 -060015from chromite.api.gen.chromite.api import test_pb2
Andrew Lamb763e3be2021-07-27 17:22:02 -060016from chromite.api.gen.chromiumos.build.api import system_image_pb2
17from chromite.api.gen.chromiumos.build.api import portage_pb2
18from chromite.api.gen.chromiumos.test.api import coverage_rule_pb2
19from chromite.api.gen.chromiumos.test.api import dut_attribute_pb2
20from chromite.api.gen.chromiumos.test.api import test_suite_pb2
21from chromite.api.gen.chromiumos.test.plan import source_test_plan_pb2
Evan Hernandeze1e05d32019-07-19 12:32:18 -060022from chromite.lib import chroot_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060023from chromite.lib import cros_build_lib
24from chromite.lib import cros_test_lib
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060025from chromite.lib import image_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060026from chromite.lib import osutils
David Wellingc1433c22021-06-25 16:29:48 +000027from chromite.lib import sysroot_lib
Alex Klein18a60af2020-06-11 12:08:47 -060028from chromite.lib.parser import package_info
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060029from chromite.scripts import cros_set_lsb_release
30from chromite.service import test as test_service
Andrew Lamb763e3be2021-07-27 17:22:02 -060031from chromite.third_party.google.protobuf import json_format
Mike Frysingere652ba12019-09-08 00:57:43 -040032from chromite.utils import key_value_store
Alex Kleina2e42c42019-04-17 16:13:19 -060033
34
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -070035class DebugInfoTestTest(cros_test_lib.MockTempDirTestCase,
36 api_config.ApiConfigMixin):
37 """Tests for the DebugInfoTest function."""
38
39 def setUp(self):
40 self.board = 'board'
41 self.chroot_path = os.path.join(self.tempdir, 'chroot')
42 self.sysroot_path = '/build/board'
43 self.full_sysroot_path = os.path.join(self.chroot_path,
44 self.sysroot_path.lstrip(os.sep))
45 osutils.SafeMakedirs(self.full_sysroot_path)
46
47 def _GetInput(self, sysroot_path=None, build_target=None):
48 """Helper to build an input message instance."""
49 proto = test_pb2.DebugInfoTestRequest()
50 if sysroot_path:
51 proto.sysroot.path = sysroot_path
52 if build_target:
53 proto.sysroot.build_target.name = build_target
54 return proto
55
56 def _GetOutput(self):
57 """Helper to get an empty output message instance."""
58 return test_pb2.DebugInfoTestResponse()
59
60 def testValidateOnly(self):
61 """Sanity check that a validate only call does not execute any logic."""
62 patch = self.PatchObject(test_service, 'DebugInfoTest')
63 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
64 test_controller.DebugInfoTest(input_msg, self._GetOutput(),
65 self.validate_only_config)
66 patch.assert_not_called()
67
Michael Mortensen85d38402019-12-12 09:50:29 -070068 def testMockError(self):
69 """Test mock error call does not execute any logic, returns error."""
70 patch = self.PatchObject(test_service, 'DebugInfoTest')
71
72 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
73 rc = test_controller.DebugInfoTest(input_msg, self._GetOutput(),
74 self.mock_error_config)
75 patch.assert_not_called()
76 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
77
78 def testMockCall(self):
79 """Test mock call does not execute any logic, returns success."""
80 patch = self.PatchObject(test_service, 'DebugInfoTest')
81
82 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
83 rc = test_controller.DebugInfoTest(input_msg, self._GetOutput(),
84 self.mock_call_config)
85 patch.assert_not_called()
86 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
87
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -070088 def testNoBuildTargetNoSysrootFails(self):
89 """Test missing build target name and sysroot path fails."""
90 input_msg = self._GetInput()
91 output_msg = self._GetOutput()
92 with self.assertRaises(cros_build_lib.DieSystemExit):
93 test_controller.DebugInfoTest(input_msg, output_msg, self.api_config)
94
95 def testDebugInfoTest(self):
96 """Call DebugInfoTest with valid sysroot_path."""
97 request = self._GetInput(sysroot_path=self.full_sysroot_path)
98
99 test_controller.DebugInfoTest(request, self._GetOutput(), self.api_config)
100
101
Alex Klein231d2da2019-07-22 16:44:45 -0600102class BuildTargetUnitTestTest(cros_test_lib.MockTempDirTestCase,
103 api_config.ApiConfigMixin):
Alex Kleina2e42c42019-04-17 16:13:19 -0600104 """Tests for the UnitTest function."""
105
Navil Perezc0b29a82020-07-07 14:17:48 +0000106 def _GetInput(self,
107 board=None,
108 result_path=None,
109 chroot_path=None,
110 cache_dir=None,
111 empty_sysroot=None,
112 packages=None,
Alex Kleinb64e5f82020-09-23 10:55:31 -0600113 blocklist=None):
Alex Kleina2e42c42019-04-17 16:13:19 -0600114 """Helper to build an input message instance."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000115 formatted_packages = []
116 for pkg in packages or []:
117 formatted_packages.append({
118 'category': pkg.category,
119 'package_name': pkg.package
120 })
Alex Kleinb64e5f82020-09-23 10:55:31 -0600121 formatted_blocklist = []
122 for pkg in blocklist or []:
123 formatted_blocklist.append({'category': pkg.category,
Alex Kleinf2674462019-05-16 16:47:24 -0600124 'package_name': pkg.package})
125
Alex Kleina2e42c42019-04-17 16:13:19 -0600126 return test_pb2.BuildTargetUnitTestRequest(
127 build_target={'name': board}, result_path=result_path,
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600128 chroot={'path': chroot_path, 'cache_dir': cache_dir},
Alex Kleinf2674462019-05-16 16:47:24 -0600129 flags={'empty_sysroot': empty_sysroot},
Alex Klein64ac34c2020-09-23 10:21:33 -0600130 packages=formatted_packages,
Alex Klein157caf42021-07-01 14:36:43 -0600131 package_blocklist=formatted_blocklist,
Alex Kleina2e42c42019-04-17 16:13:19 -0600132 )
133
134 def _GetOutput(self):
135 """Helper to get an empty output message instance."""
136 return test_pb2.BuildTargetUnitTestResponse()
137
Alex Klein231d2da2019-07-22 16:44:45 -0600138 def testValidateOnly(self):
139 """Sanity check that a validate only call does not execute any logic."""
140 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
141
142 input_msg = self._GetInput(board='board', result_path=self.tempdir)
143 test_controller.BuildTargetUnitTest(input_msg, self._GetOutput(),
144 self.validate_only_config)
145 patch.assert_not_called()
146
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700147 def testMockCall(self):
148 """Test that a mock call does not execute logic, returns mocked value."""
149 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
150
151 input_msg = self._GetInput(board='board', result_path=self.tempdir)
152 response = self._GetOutput()
153 test_controller.BuildTargetUnitTest(input_msg, response,
154 self.mock_call_config)
155 patch.assert_not_called()
156 self.assertEqual(response.tarball_path,
157 os.path.join(input_msg.result_path, 'unit_tests.tar'))
158
159 def testMockError(self):
Michael Mortensen85d38402019-12-12 09:50:29 -0700160 """Test that a mock error does not execute logic, returns error."""
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700161 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
162
163 input_msg = self._GetInput(board='board', result_path=self.tempdir)
164 response = self._GetOutput()
165 rc = test_controller.BuildTargetUnitTest(input_msg, response,
166 self.mock_error_config)
167 patch.assert_not_called()
168 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
169 self.assertTrue(response.failed_packages)
170 self.assertEqual(response.failed_packages[0].category, 'foo')
171 self.assertEqual(response.failed_packages[0].package_name, 'bar')
172 self.assertEqual(response.failed_packages[1].category, 'cat')
173 self.assertEqual(response.failed_packages[1].package_name, 'pkg')
174
Alex Kleina2e42c42019-04-17 16:13:19 -0600175 def testNoArgumentFails(self):
176 """Test no arguments fails."""
177 input_msg = self._GetInput()
178 output_msg = self._GetOutput()
179 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600180 test_controller.BuildTargetUnitTest(input_msg, output_msg,
181 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600182
183 def testNoBuildTargetFails(self):
184 """Test missing build target name fails."""
185 input_msg = self._GetInput(result_path=self.tempdir)
186 output_msg = self._GetOutput()
187 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600188 test_controller.BuildTargetUnitTest(input_msg, output_msg,
189 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600190
191 def testNoResultPathFails(self):
192 """Test missing result path fails."""
193 # Missing result_path.
194 input_msg = self._GetInput(board='board')
195 output_msg = self._GetOutput()
196 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600197 test_controller.BuildTargetUnitTest(input_msg, output_msg,
198 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600199
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')
204 input_msg = self._GetInput(board='board', result_path=self.tempdir,
205 packages=[pkg])
206 output_msg = self._GetOutput()
207 with self.assertRaises(cros_build_lib.DieSystemExit):
208 test_controller.BuildTargetUnitTest(input_msg, output_msg,
209 self.api_config)
210
Alex Kleina2e42c42019-04-17 16:13:19 -0600211 def testPackageBuildFailure(self):
212 """Test handling of raised BuildPackageFailure."""
213 tempdir = osutils.TempDir(base_dir=self.tempdir)
214 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
215
216 pkgs = ['cat/pkg', 'foo/bar']
217 expected = [('cat', 'pkg'), ('foo', 'bar')]
Alex Kleina2e42c42019-04-17 16:13:19 -0600218
Alex Klein38c7d9e2019-05-08 09:31:19 -0600219 result = test_service.BuildTargetUnitTestResult(1, None)
Alex Klein18a60af2020-06-11 12:08:47 -0600220 result.failed_cpvs = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Klein38c7d9e2019-05-08 09:31:19 -0600221 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600222
223 input_msg = self._GetInput(board='board', result_path=self.tempdir)
224 output_msg = self._GetOutput()
225
Alex Klein231d2da2019-07-22 16:44:45 -0600226 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
227 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600228
Alex Klein8cb365a2019-05-15 16:24:53 -0600229 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600230 self.assertTrue(output_msg.failed_packages)
231 failed = []
232 for pi in output_msg.failed_packages:
233 failed.append((pi.category, pi.package_name))
Mike Frysinger678735c2019-09-28 18:23:28 -0400234 self.assertCountEqual(expected, failed)
Alex Kleina2e42c42019-04-17 16:13:19 -0600235
236 def testOtherBuildScriptFailure(self):
237 """Test build script failure due to non-package emerge error."""
238 tempdir = osutils.TempDir(base_dir=self.tempdir)
239 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
240
Alex Klein38c7d9e2019-05-08 09:31:19 -0600241 result = test_service.BuildTargetUnitTestResult(1, None)
242 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600243
Alex Kleinf2674462019-05-16 16:47:24 -0600244 pkgs = ['foo/bar', 'cat/pkg']
Alex Kleinb64e5f82020-09-23 10:55:31 -0600245 blocklist = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600246 input_msg = self._GetInput(board='board', result_path=self.tempdir,
Alex Kleinb64e5f82020-09-23 10:55:31 -0600247 empty_sysroot=True, blocklist=blocklist)
Alex Kleina2e42c42019-04-17 16:13:19 -0600248 output_msg = self._GetOutput()
249
Alex Klein231d2da2019-07-22 16:44:45 -0600250 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
251 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600252
Alex Klein8cb365a2019-05-15 16:24:53 -0600253 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600254 self.assertFalse(output_msg.failed_packages)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600255
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700256 def testBuildTargetUnitTest(self):
257 """Test BuildTargetUnitTest successful call."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000258 pkgs = ['foo/bar', 'cat/pkg']
Alex Klein18a60af2020-06-11 12:08:47 -0600259 packages = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Navil Perezc0b29a82020-07-07 14:17:48 +0000260 input_msg = self._GetInput(
261 board='board', result_path=self.tempdir, packages=packages)
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700262
263 result = test_service.BuildTargetUnitTestResult(0, None)
264 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
265
266 tarball_result = os.path.join(input_msg.result_path, 'unit_tests.tar')
267 self.PatchObject(test_service, 'BuildTargetUnitTestTarball',
268 return_value=tarball_result)
269
270 response = self._GetOutput()
271 test_controller.BuildTargetUnitTest(input_msg, response,
272 self.api_config)
273 self.assertEqual(response.tarball_path,
274 os.path.join(input_msg.result_path, 'unit_tests.tar'))
275
Evan Hernandez4e388a52019-05-01 12:16:33 -0600276
C Shapiro91af1ce2021-06-17 12:42:09 -0500277class BuildTestServiceContainers(cros_test_lib.MockTestCase,
David Wellingc1433c22021-06-25 16:29:48 +0000278 api_config.ApiConfigMixin):
C Shapiro91af1ce2021-06-17 12:42:09 -0500279 """Tests for the BuildTestServiceContainers function."""
280
281 def setUp(self):
282 self.request = test_pb2.BuildTestServiceContainersRequest(
283 chroot={'path': '/path/to/chroot'},
284 build_target={'name': 'build_target'},
David Wellingc1433c22021-06-25 16:29:48 +0000285 version='R93-14033.0.0',
C Shapiro91af1ce2021-06-17 12:42:09 -0500286 )
287
C Shapiro91af1ce2021-06-17 12:42:09 -0500288 def testSuccess(self):
289 """Check passing case with mocked cros_build_lib.run."""
290 patch = self.PatchObject(
291 cros_build_lib, 'run',
292 return_value=cros_build_lib.CommandResult(returncode=0))
293
294 response = test_pb2.BuildTestServiceContainersResponse()
295 test_controller.BuildTestServiceContainers(
296 self.request,
297 response,
298 self.api_config)
299 patch.assert_called()
300 for result in response.results:
301 self.assertEqual(result.WhichOneof('result'), 'success')
302
C Shapiro91af1ce2021-06-17 12:42:09 -0500303 def testFailure(self):
304 """Check failure case with mocked cros_build_lib.run."""
305 patch = self.PatchObject(
306 cros_build_lib, 'run',
307 return_value=cros_build_lib.CommandResult(returncode=1))
308
309 response = test_pb2.BuildTestServiceContainersResponse()
310 test_controller.BuildTestServiceContainers(
311 self.request,
312 response,
313 self.api_config)
314 patch.assert_called()
315 for result in response.results:
316 self.assertEqual(result.WhichOneof('result'), 'failure')
317
318
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700319class ChromiteUnitTestTest(cros_test_lib.MockTestCase,
320 api_config.ApiConfigMixin):
321 """Tests for the ChromiteInfoTest function."""
322
323 def setUp(self):
324 self.board = 'board'
325 self.chroot_path = '/path/to/chroot'
326
327 def _GetInput(self, chroot_path=None):
328 """Helper to build an input message instance."""
329 proto = test_pb2.ChromiteUnitTestRequest(
330 chroot={'path': chroot_path},
331 )
332 return proto
333
334 def _GetOutput(self):
335 """Helper to get an empty output message instance."""
336 return test_pb2.ChromiteUnitTestResponse()
337
338 def testValidateOnly(self):
339 """Sanity check that a validate only call does not execute any logic."""
340 patch = self.PatchObject(cros_build_lib, 'run')
341
342 input_msg = self._GetInput(chroot_path=self.chroot_path)
343 test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
344 self.validate_only_config)
345 patch.assert_not_called()
346
Michael Mortensen7a860eb2019-12-03 20:25:15 -0700347 def testMockError(self):
348 """Test mock error call does not execute any logic, returns error."""
349 patch = self.PatchObject(cros_build_lib, 'run')
350
351 input_msg = self._GetInput(chroot_path=self.chroot_path)
352 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
353 self.mock_error_config)
354 patch.assert_not_called()
355 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
356
357 def testMockCall(self):
358 """Test mock call does not execute any logic, returns success."""
359 patch = self.PatchObject(cros_build_lib, 'run')
360
361 input_msg = self._GetInput(chroot_path=self.chroot_path)
362 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
363 self.mock_call_config)
364 patch.assert_not_called()
365 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
366
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700367 def testChromiteUnitTest(self):
368 """Call ChromiteUnitTest with mocked cros_build_lib.run."""
369 request = self._GetInput(chroot_path=self.chroot_path)
370 patch = self.PatchObject(
371 cros_build_lib, 'run',
372 return_value=cros_build_lib.CommandResult(returncode=0))
373
374 test_controller.ChromiteUnitTest(request, self._GetOutput(),
375 self.api_config)
376 patch.assert_called_once()
377
378
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600379class CrosSigningTestTest(cros_test_lib.RunCommandTestCase,
380 api_config.ApiConfigMixin):
381 """CrosSigningTest tests."""
382
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700383 def setUp(self):
384 self.chroot_path = '/path/to/chroot'
385
386 def _GetInput(self, chroot_path=None):
387 """Helper to build an input message instance."""
388 proto = test_pb2.CrosSigningTestRequest(
389 chroot={'path': chroot_path},
390 )
391 return proto
392
393 def _GetOutput(self):
394 """Helper to get an empty output message instance."""
395 return test_pb2.CrosSigningTestResponse()
396
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600397 def testValidateOnly(self):
398 """Sanity check that a validate only call does not execute any logic."""
399 test_controller.CrosSigningTest(None, None, self.validate_only_config)
400 self.assertFalse(self.rc.call_count)
401
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700402 def testMockCall(self):
403 """Test mock call does not execute any logic, returns success."""
404 rc = test_controller.CrosSigningTest(None, None, self.mock_call_config)
405 self.assertFalse(self.rc.call_count)
406 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
407
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700408 def testCrosSigningTest(self):
409 """Call CrosSigningTest with mocked cros_build_lib.run."""
410 request = self._GetInput(chroot_path=self.chroot_path)
411 patch = self.PatchObject(
412 cros_build_lib, 'run',
413 return_value=cros_build_lib.CommandResult(returncode=0))
414
415 test_controller.CrosSigningTest(request, self._GetOutput(),
416 self.api_config)
417 patch.assert_called_once()
418
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600419
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600420class SimpleChromeWorkflowTestTest(cros_test_lib.MockTestCase,
421 api_config.ApiConfigMixin):
422 """Test the SimpleChromeWorkflowTest endpoint."""
423
424 @staticmethod
425 def _Output():
426 return test_pb2.SimpleChromeWorkflowTestResponse()
427
David Wellingc1433c22021-06-25 16:29:48 +0000428 def _Input(self,
429 sysroot_path=None,
430 build_target=None,
431 chrome_root=None,
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600432 goma_config=None):
433 proto = test_pb2.SimpleChromeWorkflowTestRequest()
434 if sysroot_path:
435 proto.sysroot.path = sysroot_path
436 if build_target:
437 proto.sysroot.build_target.name = build_target
438 if chrome_root:
439 proto.chrome_root = chrome_root
440 if goma_config:
441 proto.goma_config = goma_config
442 return proto
443
444 def setUp(self):
445 self.chrome_path = 'path/to/chrome'
446 self.sysroot_dir = 'build/board'
447 self.build_target = 'amd64'
448 self.mock_simple_chrome_workflow_test = self.PatchObject(
449 test_service, 'SimpleChromeWorkflowTest')
450
451 def testMissingBuildTarget(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700452 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600453 input_proto = self._Input(build_target=None, sysroot_path='/sysroot/dir',
454 chrome_root='/chrome/path')
455 with self.assertRaises(cros_build_lib.DieSystemExit):
456 test_controller.SimpleChromeWorkflowTest(input_proto, None,
457 self.api_config)
458
459 def testMissingSysrootPath(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700460 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600461 input_proto = self._Input(build_target='board', sysroot_path=None,
462 chrome_root='/chrome/path')
463 with self.assertRaises(cros_build_lib.DieSystemExit):
464 test_controller.SimpleChromeWorkflowTest(input_proto, None,
465 self.api_config)
466
467 def testMissingChromeRoot(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700468 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600469 input_proto = self._Input(build_target='board', sysroot_path='/sysroot/dir',
470 chrome_root=None)
471 with self.assertRaises(cros_build_lib.DieSystemExit):
472 test_controller.SimpleChromeWorkflowTest(input_proto, None,
473 self.api_config)
474
475 def testSimpleChromeWorkflowTest(self):
476 """Call SimpleChromeWorkflowTest with valid args and temp dir."""
477 request = self._Input(sysroot_path='sysroot_path', build_target='board',
478 chrome_root='/path/to/chrome')
479 response = self._Output()
480
481 test_controller.SimpleChromeWorkflowTest(request, response, self.api_config)
482 self.mock_simple_chrome_workflow_test.assert_called()
483
484 def testValidateOnly(self):
485 request = self._Input(sysroot_path='sysroot_path', build_target='board',
486 chrome_root='/path/to/chrome')
487 test_controller.SimpleChromeWorkflowTest(request, self._Output(),
488 self.validate_only_config)
489 self.mock_simple_chrome_workflow_test.assert_not_called()
490
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700491 def testMockCall(self):
492 """Test mock call does not execute any logic, returns success."""
493 patch = self.mock_simple_chrome_workflow_test = self.PatchObject(
494 test_service, 'SimpleChromeWorkflowTest')
495
496 request = self._Input(sysroot_path='sysroot_path', build_target='board',
497 chrome_root='/path/to/chrome')
498 rc = test_controller.SimpleChromeWorkflowTest(request, self._Output(),
499 self.mock_call_config)
500 patch.assert_not_called()
501 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
502
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600503
Alex Klein231d2da2019-07-22 16:44:45 -0600504class VmTestTest(cros_test_lib.RunCommandTestCase, api_config.ApiConfigMixin):
Evan Hernandez4e388a52019-05-01 12:16:33 -0600505 """Test the VmTest endpoint."""
506
507 def _GetInput(self, **kwargs):
508 values = dict(
509 build_target=common_pb2.BuildTarget(name='target'),
Alex Klein311b8022019-06-05 16:00:07 -0600510 vm_path=common_pb2.Path(path='/path/to/image.bin',
511 location=common_pb2.Path.INSIDE),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600512 test_harness=test_pb2.VmTestRequest.TAST,
513 vm_tests=[test_pb2.VmTestRequest.VmTest(pattern='suite')],
514 ssh_options=test_pb2.VmTestRequest.SshOptions(
Alex Klein231d2da2019-07-22 16:44:45 -0600515 port=1234, private_key_path={'path': '/path/to/id_rsa',
Alex Kleinaa705412019-06-04 15:00:30 -0600516 'location': common_pb2.Path.INSIDE}),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600517 )
518 values.update(kwargs)
519 return test_pb2.VmTestRequest(**values)
520
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700521 def _Output(self):
522 return test_pb2.VmTestResponse()
523
Alex Klein231d2da2019-07-22 16:44:45 -0600524 def testValidateOnly(self):
525 """Sanity check that a validate only call does not execute any logic."""
526 test_controller.VmTest(self._GetInput(), None, self.validate_only_config)
527 self.assertEqual(0, self.rc.call_count)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600528
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700529 def testMockCall(self):
530 """Test mock call does not execute any logic."""
531 patch = self.PatchObject(cros_build_lib, 'run')
532
533 request = self._GetInput()
534 response = self._Output()
535 # VmTest does not return a value, checking mocked value is flagged by lint.
536 test_controller.VmTest(request, response, self.mock_call_config)
537 patch.assert_not_called()
538
Evan Hernandez4e388a52019-05-01 12:16:33 -0600539 def testTastAllOptions(self):
540 """Test VmTest for Tast with all options set."""
Alex Klein231d2da2019-07-22 16:44:45 -0600541 test_controller.VmTest(self._GetInput(), None, self.api_config)
542 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700543 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600544 '--board', 'target',
545 '--image-path', '/path/to/image.bin',
546 '--tast', 'suite',
547 '--ssh-port', '1234',
548 '--private-key', '/path/to/id_rsa',
549 ])
550
551 def testAutotestAllOptions(self):
552 """Test VmTest for Autotest with all options set."""
553 input_proto = self._GetInput(test_harness=test_pb2.VmTestRequest.AUTOTEST)
Alex Klein231d2da2019-07-22 16:44:45 -0600554 test_controller.VmTest(input_proto, None, self.api_config)
555 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700556 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600557 '--board', 'target',
558 '--image-path', '/path/to/image.bin',
559 '--autotest', 'suite',
560 '--ssh-port', '1234',
561 '--private-key', '/path/to/id_rsa',
Greg Edelstondcb0e912020-08-31 11:09:40 -0600562 '--test_that-args=--allow-chrome-crashes',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600563 ])
564
565 def testMissingBuildTarget(self):
566 """Test VmTest dies when build_target not set."""
567 input_proto = self._GetInput(build_target=None)
568 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600569 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600570
571 def testMissingVmImage(self):
572 """Test VmTest dies when vm_image not set."""
Alex Klein311b8022019-06-05 16:00:07 -0600573 input_proto = self._GetInput(vm_path=None)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600574 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600575 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600576
577 def testMissingTestHarness(self):
578 """Test VmTest dies when test_harness not specified."""
579 input_proto = self._GetInput(
580 test_harness=test_pb2.VmTestRequest.UNSPECIFIED)
581 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600582 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600583
584 def testMissingVmTests(self):
585 """Test VmTest dies when vm_tests not set."""
586 input_proto = self._GetInput(vm_tests=[])
587 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600588 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600589
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700590 def testVmTest(self):
591 """Call VmTest with valid args and temp dir."""
592 request = self._GetInput()
593 response = self._Output()
594 patch = self.PatchObject(
595 cros_build_lib, 'run',
596 return_value=cros_build_lib.CommandResult(returncode=0))
597
598 test_controller.VmTest(request, response, self.api_config)
599 patch.assert_called()
600
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600601
Alex Klein231d2da2019-07-22 16:44:45 -0600602class MoblabVmTestTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600603 """Test the MoblabVmTest endpoint."""
604
605 @staticmethod
606 def _Payload(path):
607 return test_pb2.MoblabVmTestRequest.Payload(
608 path=common_pb2.Path(path=path))
609
610 @staticmethod
611 def _Output():
612 return test_pb2.MoblabVmTestResponse()
613
614 def _Input(self):
615 return test_pb2.MoblabVmTestRequest(
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600616 chroot=common_pb2.Chroot(path=self.chroot_dir),
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600617 image_payload=self._Payload(self.image_payload_dir),
618 cache_payloads=[self._Payload(self.autotest_payload_dir)])
619
620 def setUp(self):
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600621 self.chroot_dir = '/chroot'
622 self.chroot_tmp_dir = '/chroot/tmp'
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600623 self.image_payload_dir = '/payloads/image'
624 self.autotest_payload_dir = '/payloads/autotest'
625 self.builder = 'moblab-generic-vm/R12-3.4.5-67.890'
626 self.image_cache_dir = '/mnt/moblab/cache'
627 self.image_mount_dir = '/mnt/image'
628
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600629 self.PatchObject(chroot_lib.Chroot, 'tempdir', osutils.TempDir)
Evan Hernandez655e8042019-06-13 12:50:44 -0600630
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600631 self.mock_create_moblab_vms = self.PatchObject(
632 test_service, 'CreateMoblabVm')
633 self.mock_prepare_moblab_vm_image_cache = self.PatchObject(
634 test_service, 'PrepareMoblabVmImageCache',
635 return_value=self.image_cache_dir)
636 self.mock_run_moblab_vm_tests = self.PatchObject(
637 test_service, 'RunMoblabVmTest')
638 self.mock_validate_moblab_vm_tests = self.PatchObject(
639 test_service, 'ValidateMoblabVmTest')
640
641 @contextlib.contextmanager
Alex Klein38c7d9e2019-05-08 09:31:19 -0600642 def MockLoopbackPartitions(*_args, **_kwargs):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600643 mount = mock.MagicMock()
Evan Hernandez40ee7452019-06-13 12:51:43 -0600644 mount.Mount.return_value = [self.image_mount_dir]
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600645 yield mount
Alex Klein231d2da2019-07-22 16:44:45 -0600646
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600647 self.PatchObject(image_lib, 'LoopbackPartitions', MockLoopbackPartitions)
648
Alex Klein231d2da2019-07-22 16:44:45 -0600649 def testValidateOnly(self):
650 """Sanity check that a validate only call does not execute any logic."""
651 test_controller.MoblabVmTest(self._Input(), self._Output(),
652 self.validate_only_config)
653 self.mock_create_moblab_vms.assert_not_called()
654
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700655 def testMockCall(self):
656 """Test mock call does not execute any logic."""
657 patch = self.PatchObject(key_value_store, 'LoadFile')
658
659 # MoblabVmTest does not return a value, checking mocked value is flagged by
660 # lint.
661 test_controller.MoblabVmTest(self._Input(), self._Output(),
662 self.mock_call_config)
663 patch.assert_not_called()
664
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600665 def testImageContainsBuilder(self):
666 """MoblabVmTest calls service with correct args."""
667 request = self._Input()
668 response = self._Output()
669
670 self.PatchObject(
Mike Frysingere652ba12019-09-08 00:57:43 -0400671 key_value_store, 'LoadFile',
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600672 return_value={cros_set_lsb_release.LSB_KEY_BUILDER_PATH: self.builder})
673
Alex Klein231d2da2019-07-22 16:44:45 -0600674 test_controller.MoblabVmTest(request, response, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600675
676 self.assertEqual(
677 self.mock_create_moblab_vms.call_args_list,
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600678 [mock.call(mock.ANY, self.chroot_dir, self.image_payload_dir)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600679 self.assertEqual(
680 self.mock_prepare_moblab_vm_image_cache.call_args_list,
681 [mock.call(mock.ANY, self.builder, [self.autotest_payload_dir])])
682 self.assertEqual(
683 self.mock_run_moblab_vm_tests.call_args_list,
Evan Hernandez655e8042019-06-13 12:50:44 -0600684 [mock.call(mock.ANY, mock.ANY, self.builder, self.image_cache_dir,
685 mock.ANY)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600686 self.assertEqual(
687 self.mock_validate_moblab_vm_tests.call_args_list,
688 [mock.call(mock.ANY)])
689
690 def testImageMissingBuilder(self):
691 """MoblabVmTest dies when builder path not found in lsb-release."""
692 request = self._Input()
693 response = self._Output()
694
Mike Frysingere652ba12019-09-08 00:57:43 -0400695 self.PatchObject(key_value_store, 'LoadFile', return_value={})
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600696
697 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600698 test_controller.MoblabVmTest(request, response, self.api_config)
David Wellingc1433c22021-06-25 16:29:48 +0000699
700
701class GetArtifactsTest(cros_test_lib.MockTempDirTestCase):
702 """Test GetArtifacts."""
703
704 CODE_COVERAGE_LLVM_ARTIFACT_TYPE = (
705 common_pb2.ArtifactsByService.Test.ArtifactType.CODE_COVERAGE_LLVM_JSON
706 )
George Engelbrecht764b1cd2021-06-18 17:01:07 -0600707 UNIT_TEST_ARTIFACT_TYPE = (
708 common_pb2.ArtifactsByService.Test.ArtifactType.UNIT_TESTS
709 )
David Wellingc1433c22021-06-25 16:29:48 +0000710
711 def setUp(self):
712 """Set up the class for tests."""
713 chroot_dir = os.path.join(self.tempdir, 'chroot')
714 osutils.SafeMakedirs(chroot_dir)
715 osutils.SafeMakedirs(os.path.join(chroot_dir, 'tmp'))
716 self.chroot = chroot_lib.Chroot(chroot_dir)
717
718 sysroot_path = os.path.join(chroot_dir, 'build', 'board')
719 osutils.SafeMakedirs(sysroot_path)
720 self.sysroot = sysroot_lib.Sysroot(sysroot_path)
721
722 def testReturnsEmptyListWhenNoOutputArtifactsProvided(self):
723 """Test empty list is returned when there are no output_artifacts."""
724 result = test_controller.GetArtifacts(
725 common_pb2.ArtifactsByService.Test(output_artifacts=[]),
726 self.chroot, self.sysroot, self.tempdir)
727
728 self.assertEqual(len(result), 0)
729
730 def testShouldCallBundleCodeCoverageLlvmJsonForEachValidArtifact(self):
731 """Test BundleCodeCoverageLlvmJson is called on each valid artifact."""
732 BundleCodeCoverageLlvmJson_mock = self.PatchObject(
733 test_service, 'BundleCodeCoverageLlvmJson', return_value='test')
734
735 test_controller.GetArtifacts(
736 common_pb2.ArtifactsByService.Test(output_artifacts=[
737 # Valid
738 common_pb2.ArtifactsByService.Test.ArtifactInfo(
739 artifact_types=[
740 self.CODE_COVERAGE_LLVM_ARTIFACT_TYPE
741 ]
742 ),
743
744 # Invalid
745 common_pb2.ArtifactsByService.Test.ArtifactInfo(
746 artifact_types=[
747 common_pb2.ArtifactsByService.Test.ArtifactType.UNIT_TESTS
748 ]
749 ),
750 ]),
751 self.chroot, self.sysroot, self.tempdir)
752
753 BundleCodeCoverageLlvmJson_mock.assert_called_once()
754
755 def testShouldReturnValidResult(self):
756 """Test result contains paths and code_coverage_llvm_json type."""
757 self.PatchObject(test_service, 'BundleCodeCoverageLlvmJson',
758 return_value='test')
George Engelbrecht764b1cd2021-06-18 17:01:07 -0600759 self.PatchObject(test_service, 'BuildTargetUnitTestTarball',
760 return_value='unit_tests.tar')
David Wellingc1433c22021-06-25 16:29:48 +0000761
762 result = test_controller.GetArtifacts(
763 common_pb2.ArtifactsByService.Test(output_artifacts=[
764 # Valid
765 common_pb2.ArtifactsByService.Test.ArtifactInfo(
766 artifact_types=[
George Engelbrecht764b1cd2021-06-18 17:01:07 -0600767 self.UNIT_TEST_ARTIFACT_TYPE
768 ]
769 ),
770 common_pb2.ArtifactsByService.Test.ArtifactInfo(
771 artifact_types=[
David Wellingc1433c22021-06-25 16:29:48 +0000772 self.CODE_COVERAGE_LLVM_ARTIFACT_TYPE
773 ]
774 ),
775 ]),
776 self.chroot, self.sysroot, self.tempdir)
777
George Engelbrecht764b1cd2021-06-18 17:01:07 -0600778 self.assertEqual(result[0]['paths'], ['unit_tests.tar'])
779 self.assertEqual(result[0]['type'], self.UNIT_TEST_ARTIFACT_TYPE)
780 self.assertEqual(result[1]['paths'], ['test'])
781 self.assertEqual(result[1]['type'], self.CODE_COVERAGE_LLVM_ARTIFACT_TYPE)
Andrew Lamb763e3be2021-07-27 17:22:02 -0600782
783
784class GetCoverageRulesTest(cros_test_lib.RunCommandTempDirTestCase,
785 api_config.ApiConfigMixin):
786 """Tests for GetCoverageRules."""
787
788 @staticmethod
789 def _Input():
790 """Returns a sample GetCoverageRulesRequest for testing."""
791 return test_pb2.GetCoverageRulesRequest(
792 source_test_plans=[
793 source_test_plan_pb2.SourceTestPlan(
794 requirements=source_test_plan_pb2.SourceTestPlan.Requirements(
795 kernel_versions=source_test_plan_pb2.SourceTestPlan
796 .Requirements.KernelVersions()),
797 test_tags=['kernel']),
798 ],
799 build_metadata_list=system_image_pb2.SystemImage
800 .BuildMetadataList(values=[
801 system_image_pb2.SystemImage.BuildMetadata(
802 build_target=system_image_pb2.SystemImage.BuildTarget(
803 portage_build_target=portage_pb2.Portage.BuildTarget(
804 overlay_name='overlayA')),
805 package_summary=system_image_pb2.SystemImage.BuildMetadata
806 .PackageSummary(
807 kernel=system_image_pb2.SystemImage.BuildMetadata.Kernel(
808 version='4.4')))
809 ]),
810 dut_attribute_list=dut_attribute_pb2.DutAttributeList(dut_attributes=[
811 dut_attribute_pb2.DutAttribute(
812 id=dut_attribute_pb2.DutAttribute.Id(
813 value='system_build_target'))
814 ]))
815
816 @staticmethod
817 def _Output():
818 """Returns a sample GetCoverageRulesResponse for testing."""
819 return test_pb2.GetCoverageRulesResponse(coverage_rules=[
820 coverage_rule_pb2.CoverageRule(
821 name='kernel:4.4',
822 test_suites=[
823 test_suite_pb2.TestSuite(
824 test_case_tag_criteria=test_suite_pb2.TestSuite
825 .TestCaseTagCriteria(tags=['kernel']))
826 ],
827 dut_criteria=[
828 dut_attribute_pb2.DutCriterion(
829 attribute_id=dut_attribute_pb2.DutAttribute.Id(
830 value='system_build_target'),
831 values=['overlayA'],
832 )
833 ])
834 ])
835
836 @staticmethod
837 def _write_coverage_rules(path, coverage_rules):
838 """Write a list of CoverageRules in the same format as testplan."""
839 osutils.WriteFile(
840 path, '\n'.join(
841 json_format.MessageToJson(rule).replace('\n', '')
842 for rule in coverage_rules))
843
844 def testWritesInputsAndReturnsCoverageRules(self):
845 """Test inputs are written, and output of testplan is parsed."""
846 output_proto = test_pb2.GetCoverageRulesResponse()
847
848 self.rc.SetDefaultCmdResult(
849 side_effect=lambda _: self._write_coverage_rules(
850 os.path.join(self.tempdir, 'out.jsonpb'),
851 self._Output().coverage_rules))
852 self.PatchObject(osutils.TempDir, '__enter__', return_value=self.tempdir)
853
854 test_controller.GetCoverageRules(self._Input(), output_proto,
855 self.api_config)
856
857 build_metadata_list = system_image_pb2.SystemImage.BuildMetadataList()
858 json_format.Parse(
859 osutils.ReadFile(
860 os.path.join(self.tempdir, 'build_metadata_list.jsonpb')),
861 build_metadata_list)
862 self.assertEqual(build_metadata_list, self._Input().build_metadata_list)
863
864 dut_attribute_list = dut_attribute_pb2.DutAttributeList()
865 json_format.Parse(
866 osutils.ReadFile(
867 os.path.join(self.tempdir, 'dut_attribute_list.jsonpb')),
868 dut_attribute_list)
869 self.assertEqual(dut_attribute_list, self._Input().dut_attribute_list)
870
871 self.assertEqual(output_proto, self._Output())