blob: 5513448315604df24ce4cd802a897c0fb8178d45 [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
Andrew Lambd814afa2021-08-11 11:04:20 -060018from chromite.api.gen.chromiumos.config.payload import flat_config_pb2
19from chromite.api.gen.chromiumos.config.api import design_pb2
20from chromite.api.gen.chromiumos.config.api import design_id_pb2
Andrew Lamb763e3be2021-07-27 17:22:02 -060021from chromite.api.gen.chromiumos.test.api import coverage_rule_pb2
22from chromite.api.gen.chromiumos.test.api import dut_attribute_pb2
23from chromite.api.gen.chromiumos.test.api import test_suite_pb2
24from chromite.api.gen.chromiumos.test.plan import source_test_plan_pb2
Evan Hernandeze1e05d32019-07-19 12:32:18 -060025from chromite.lib import chroot_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060026from chromite.lib import cros_build_lib
27from chromite.lib import cros_test_lib
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060028from chromite.lib import image_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060029from chromite.lib import osutils
David Wellingc1433c22021-06-25 16:29:48 +000030from chromite.lib import sysroot_lib
Alex Klein18a60af2020-06-11 12:08:47 -060031from chromite.lib.parser import package_info
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060032from chromite.scripts import cros_set_lsb_release
33from chromite.service import test as test_service
Andrew Lamb763e3be2021-07-27 17:22:02 -060034from chromite.third_party.google.protobuf import json_format
Mike Frysingere652ba12019-09-08 00:57:43 -040035from chromite.utils import key_value_store
Alex Kleina2e42c42019-04-17 16:13:19 -060036
37
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -070038class DebugInfoTestTest(cros_test_lib.MockTempDirTestCase,
39 api_config.ApiConfigMixin):
40 """Tests for the DebugInfoTest function."""
41
42 def setUp(self):
43 self.board = 'board'
44 self.chroot_path = os.path.join(self.tempdir, 'chroot')
45 self.sysroot_path = '/build/board'
46 self.full_sysroot_path = os.path.join(self.chroot_path,
47 self.sysroot_path.lstrip(os.sep))
48 osutils.SafeMakedirs(self.full_sysroot_path)
49
50 def _GetInput(self, sysroot_path=None, build_target=None):
51 """Helper to build an input message instance."""
52 proto = test_pb2.DebugInfoTestRequest()
53 if sysroot_path:
54 proto.sysroot.path = sysroot_path
55 if build_target:
56 proto.sysroot.build_target.name = build_target
57 return proto
58
59 def _GetOutput(self):
60 """Helper to get an empty output message instance."""
61 return test_pb2.DebugInfoTestResponse()
62
63 def testValidateOnly(self):
64 """Sanity check that a validate only call does not execute any logic."""
65 patch = self.PatchObject(test_service, 'DebugInfoTest')
66 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
67 test_controller.DebugInfoTest(input_msg, self._GetOutput(),
68 self.validate_only_config)
69 patch.assert_not_called()
70
Michael Mortensen85d38402019-12-12 09:50:29 -070071 def testMockError(self):
72 """Test mock error call does not execute any logic, returns error."""
73 patch = self.PatchObject(test_service, 'DebugInfoTest')
74
75 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
76 rc = test_controller.DebugInfoTest(input_msg, self._GetOutput(),
77 self.mock_error_config)
78 patch.assert_not_called()
79 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
80
81 def testMockCall(self):
82 """Test mock call does not execute any logic, returns success."""
83 patch = self.PatchObject(test_service, 'DebugInfoTest')
84
85 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
86 rc = test_controller.DebugInfoTest(input_msg, self._GetOutput(),
87 self.mock_call_config)
88 patch.assert_not_called()
89 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
90
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -070091 def testNoBuildTargetNoSysrootFails(self):
92 """Test missing build target name and sysroot path fails."""
93 input_msg = self._GetInput()
94 output_msg = self._GetOutput()
95 with self.assertRaises(cros_build_lib.DieSystemExit):
96 test_controller.DebugInfoTest(input_msg, output_msg, self.api_config)
97
98 def testDebugInfoTest(self):
99 """Call DebugInfoTest with valid sysroot_path."""
100 request = self._GetInput(sysroot_path=self.full_sysroot_path)
101
102 test_controller.DebugInfoTest(request, self._GetOutput(), self.api_config)
103
104
Alex Klein231d2da2019-07-22 16:44:45 -0600105class BuildTargetUnitTestTest(cros_test_lib.MockTempDirTestCase,
106 api_config.ApiConfigMixin):
Alex Kleina2e42c42019-04-17 16:13:19 -0600107 """Tests for the UnitTest function."""
108
Navil Perezc0b29a82020-07-07 14:17:48 +0000109 def _GetInput(self,
110 board=None,
111 result_path=None,
112 chroot_path=None,
113 cache_dir=None,
114 empty_sysroot=None,
115 packages=None,
Alex Kleinb64e5f82020-09-23 10:55:31 -0600116 blocklist=None):
Alex Kleina2e42c42019-04-17 16:13:19 -0600117 """Helper to build an input message instance."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000118 formatted_packages = []
119 for pkg in packages or []:
120 formatted_packages.append({
121 'category': pkg.category,
122 'package_name': pkg.package
123 })
Alex Kleinb64e5f82020-09-23 10:55:31 -0600124 formatted_blocklist = []
125 for pkg in blocklist or []:
126 formatted_blocklist.append({'category': pkg.category,
Alex Kleinf2674462019-05-16 16:47:24 -0600127 'package_name': pkg.package})
128
Alex Kleina2e42c42019-04-17 16:13:19 -0600129 return test_pb2.BuildTargetUnitTestRequest(
130 build_target={'name': board}, result_path=result_path,
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600131 chroot={'path': chroot_path, 'cache_dir': cache_dir},
Alex Kleinf2674462019-05-16 16:47:24 -0600132 flags={'empty_sysroot': empty_sysroot},
Alex Klein64ac34c2020-09-23 10:21:33 -0600133 packages=formatted_packages,
Alex Klein157caf42021-07-01 14:36:43 -0600134 package_blocklist=formatted_blocklist,
Alex Kleina2e42c42019-04-17 16:13:19 -0600135 )
136
137 def _GetOutput(self):
138 """Helper to get an empty output message instance."""
139 return test_pb2.BuildTargetUnitTestResponse()
140
Alex Klein231d2da2019-07-22 16:44:45 -0600141 def testValidateOnly(self):
142 """Sanity check that a validate only call does not execute any logic."""
143 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
144
145 input_msg = self._GetInput(board='board', result_path=self.tempdir)
146 test_controller.BuildTargetUnitTest(input_msg, self._GetOutput(),
147 self.validate_only_config)
148 patch.assert_not_called()
149
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700150 def testMockCall(self):
151 """Test that a mock call does not execute logic, returns mocked value."""
152 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
153
154 input_msg = self._GetInput(board='board', result_path=self.tempdir)
155 response = self._GetOutput()
156 test_controller.BuildTargetUnitTest(input_msg, response,
157 self.mock_call_config)
158 patch.assert_not_called()
159 self.assertEqual(response.tarball_path,
160 os.path.join(input_msg.result_path, 'unit_tests.tar'))
161
162 def testMockError(self):
Michael Mortensen85d38402019-12-12 09:50:29 -0700163 """Test that a mock error does not execute logic, returns error."""
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700164 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
165
166 input_msg = self._GetInput(board='board', result_path=self.tempdir)
167 response = self._GetOutput()
168 rc = test_controller.BuildTargetUnitTest(input_msg, response,
169 self.mock_error_config)
170 patch.assert_not_called()
171 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
172 self.assertTrue(response.failed_packages)
173 self.assertEqual(response.failed_packages[0].category, 'foo')
174 self.assertEqual(response.failed_packages[0].package_name, 'bar')
175 self.assertEqual(response.failed_packages[1].category, 'cat')
176 self.assertEqual(response.failed_packages[1].package_name, 'pkg')
177
Alex Kleina2e42c42019-04-17 16:13:19 -0600178 def testNoArgumentFails(self):
179 """Test no arguments fails."""
180 input_msg = self._GetInput()
181 output_msg = self._GetOutput()
182 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600183 test_controller.BuildTargetUnitTest(input_msg, output_msg,
184 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600185
186 def testNoBuildTargetFails(self):
187 """Test missing build target name fails."""
188 input_msg = self._GetInput(result_path=self.tempdir)
189 output_msg = self._GetOutput()
190 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600191 test_controller.BuildTargetUnitTest(input_msg, output_msg,
192 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600193
194 def testNoResultPathFails(self):
195 """Test missing result path fails."""
196 # Missing result_path.
197 input_msg = self._GetInput(board='board')
198 output_msg = self._GetOutput()
199 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600200 test_controller.BuildTargetUnitTest(input_msg, output_msg,
201 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600202
Alex Klein64ac34c2020-09-23 10:21:33 -0600203 def testInvalidPackageFails(self):
204 """Test missing result path fails."""
205 # Missing result_path.
206 pkg = package_info.PackageInfo(package='bar')
207 input_msg = self._GetInput(board='board', result_path=self.tempdir,
208 packages=[pkg])
209 output_msg = self._GetOutput()
210 with self.assertRaises(cros_build_lib.DieSystemExit):
211 test_controller.BuildTargetUnitTest(input_msg, output_msg,
212 self.api_config)
213
Alex Kleina2e42c42019-04-17 16:13:19 -0600214 def testPackageBuildFailure(self):
215 """Test handling of raised BuildPackageFailure."""
216 tempdir = osutils.TempDir(base_dir=self.tempdir)
217 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
218
219 pkgs = ['cat/pkg', 'foo/bar']
220 expected = [('cat', 'pkg'), ('foo', 'bar')]
Alex Kleina2e42c42019-04-17 16:13:19 -0600221
Alex Klein38c7d9e2019-05-08 09:31:19 -0600222 result = test_service.BuildTargetUnitTestResult(1, None)
Alex Klein18a60af2020-06-11 12:08:47 -0600223 result.failed_cpvs = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Klein38c7d9e2019-05-08 09:31:19 -0600224 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600225
226 input_msg = self._GetInput(board='board', result_path=self.tempdir)
227 output_msg = self._GetOutput()
228
Alex Klein231d2da2019-07-22 16:44:45 -0600229 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
230 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600231
Alex Klein8cb365a2019-05-15 16:24:53 -0600232 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600233 self.assertTrue(output_msg.failed_packages)
234 failed = []
235 for pi in output_msg.failed_packages:
236 failed.append((pi.category, pi.package_name))
Mike Frysinger678735c2019-09-28 18:23:28 -0400237 self.assertCountEqual(expected, failed)
Alex Kleina2e42c42019-04-17 16:13:19 -0600238
239 def testOtherBuildScriptFailure(self):
240 """Test build script failure due to non-package emerge error."""
241 tempdir = osutils.TempDir(base_dir=self.tempdir)
242 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
243
Alex Klein38c7d9e2019-05-08 09:31:19 -0600244 result = test_service.BuildTargetUnitTestResult(1, None)
245 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600246
Alex Kleinf2674462019-05-16 16:47:24 -0600247 pkgs = ['foo/bar', 'cat/pkg']
Alex Kleinb64e5f82020-09-23 10:55:31 -0600248 blocklist = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600249 input_msg = self._GetInput(board='board', result_path=self.tempdir,
Alex Kleinb64e5f82020-09-23 10:55:31 -0600250 empty_sysroot=True, blocklist=blocklist)
Alex Kleina2e42c42019-04-17 16:13:19 -0600251 output_msg = self._GetOutput()
252
Alex Klein231d2da2019-07-22 16:44:45 -0600253 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
254 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600255
Alex Klein8cb365a2019-05-15 16:24:53 -0600256 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600257 self.assertFalse(output_msg.failed_packages)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600258
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700259 def testBuildTargetUnitTest(self):
260 """Test BuildTargetUnitTest successful call."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000261 pkgs = ['foo/bar', 'cat/pkg']
Alex Klein18a60af2020-06-11 12:08:47 -0600262 packages = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Navil Perezc0b29a82020-07-07 14:17:48 +0000263 input_msg = self._GetInput(
264 board='board', result_path=self.tempdir, packages=packages)
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700265
266 result = test_service.BuildTargetUnitTestResult(0, None)
267 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
268
269 tarball_result = os.path.join(input_msg.result_path, 'unit_tests.tar')
270 self.PatchObject(test_service, 'BuildTargetUnitTestTarball',
271 return_value=tarball_result)
272
273 response = self._GetOutput()
274 test_controller.BuildTargetUnitTest(input_msg, response,
275 self.api_config)
276 self.assertEqual(response.tarball_path,
277 os.path.join(input_msg.result_path, 'unit_tests.tar'))
278
Evan Hernandez4e388a52019-05-01 12:16:33 -0600279
C Shapiro91af1ce2021-06-17 12:42:09 -0500280class BuildTestServiceContainers(cros_test_lib.MockTestCase,
David Wellingc1433c22021-06-25 16:29:48 +0000281 api_config.ApiConfigMixin):
C Shapiro91af1ce2021-06-17 12:42:09 -0500282 """Tests for the BuildTestServiceContainers function."""
283
284 def setUp(self):
285 self.request = test_pb2.BuildTestServiceContainersRequest(
286 chroot={'path': '/path/to/chroot'},
287 build_target={'name': 'build_target'},
David Wellingc1433c22021-06-25 16:29:48 +0000288 version='R93-14033.0.0',
C Shapiro91af1ce2021-06-17 12:42:09 -0500289 )
290
C Shapiro91af1ce2021-06-17 12:42:09 -0500291 def testSuccess(self):
292 """Check passing case with mocked cros_build_lib.run."""
293 patch = self.PatchObject(
294 cros_build_lib, 'run',
295 return_value=cros_build_lib.CommandResult(returncode=0))
296
297 response = test_pb2.BuildTestServiceContainersResponse()
298 test_controller.BuildTestServiceContainers(
299 self.request,
300 response,
301 self.api_config)
302 patch.assert_called()
303 for result in response.results:
304 self.assertEqual(result.WhichOneof('result'), 'success')
305
C Shapiro91af1ce2021-06-17 12:42:09 -0500306 def testFailure(self):
307 """Check failure case with mocked cros_build_lib.run."""
308 patch = self.PatchObject(
309 cros_build_lib, 'run',
310 return_value=cros_build_lib.CommandResult(returncode=1))
311
312 response = test_pb2.BuildTestServiceContainersResponse()
313 test_controller.BuildTestServiceContainers(
314 self.request,
315 response,
316 self.api_config)
317 patch.assert_called()
318 for result in response.results:
319 self.assertEqual(result.WhichOneof('result'), 'failure')
320
321
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700322class ChromiteUnitTestTest(cros_test_lib.MockTestCase,
323 api_config.ApiConfigMixin):
324 """Tests for the ChromiteInfoTest function."""
325
326 def setUp(self):
327 self.board = 'board'
328 self.chroot_path = '/path/to/chroot'
329
330 def _GetInput(self, chroot_path=None):
331 """Helper to build an input message instance."""
332 proto = test_pb2.ChromiteUnitTestRequest(
333 chroot={'path': chroot_path},
334 )
335 return proto
336
337 def _GetOutput(self):
338 """Helper to get an empty output message instance."""
339 return test_pb2.ChromiteUnitTestResponse()
340
341 def testValidateOnly(self):
342 """Sanity check that a validate only call does not execute any logic."""
343 patch = self.PatchObject(cros_build_lib, 'run')
344
345 input_msg = self._GetInput(chroot_path=self.chroot_path)
346 test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
347 self.validate_only_config)
348 patch.assert_not_called()
349
Michael Mortensen7a860eb2019-12-03 20:25:15 -0700350 def testMockError(self):
351 """Test mock error call does not execute any logic, returns error."""
352 patch = self.PatchObject(cros_build_lib, 'run')
353
354 input_msg = self._GetInput(chroot_path=self.chroot_path)
355 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
356 self.mock_error_config)
357 patch.assert_not_called()
358 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
359
360 def testMockCall(self):
361 """Test mock call does not execute any logic, returns success."""
362 patch = self.PatchObject(cros_build_lib, 'run')
363
364 input_msg = self._GetInput(chroot_path=self.chroot_path)
365 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
366 self.mock_call_config)
367 patch.assert_not_called()
368 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
369
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700370 def testChromiteUnitTest(self):
371 """Call ChromiteUnitTest with mocked cros_build_lib.run."""
372 request = self._GetInput(chroot_path=self.chroot_path)
373 patch = self.PatchObject(
374 cros_build_lib, 'run',
375 return_value=cros_build_lib.CommandResult(returncode=0))
376
377 test_controller.ChromiteUnitTest(request, self._GetOutput(),
378 self.api_config)
379 patch.assert_called_once()
380
381
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600382class CrosSigningTestTest(cros_test_lib.RunCommandTestCase,
383 api_config.ApiConfigMixin):
384 """CrosSigningTest tests."""
385
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700386 def setUp(self):
387 self.chroot_path = '/path/to/chroot'
388
389 def _GetInput(self, chroot_path=None):
390 """Helper to build an input message instance."""
391 proto = test_pb2.CrosSigningTestRequest(
392 chroot={'path': chroot_path},
393 )
394 return proto
395
396 def _GetOutput(self):
397 """Helper to get an empty output message instance."""
398 return test_pb2.CrosSigningTestResponse()
399
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600400 def testValidateOnly(self):
401 """Sanity check that a validate only call does not execute any logic."""
402 test_controller.CrosSigningTest(None, None, self.validate_only_config)
403 self.assertFalse(self.rc.call_count)
404
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700405 def testMockCall(self):
406 """Test mock call does not execute any logic, returns success."""
407 rc = test_controller.CrosSigningTest(None, None, self.mock_call_config)
408 self.assertFalse(self.rc.call_count)
409 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
410
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700411 def testCrosSigningTest(self):
412 """Call CrosSigningTest with mocked cros_build_lib.run."""
413 request = self._GetInput(chroot_path=self.chroot_path)
414 patch = self.PatchObject(
415 cros_build_lib, 'run',
416 return_value=cros_build_lib.CommandResult(returncode=0))
417
418 test_controller.CrosSigningTest(request, self._GetOutput(),
419 self.api_config)
420 patch.assert_called_once()
421
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600422
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600423class SimpleChromeWorkflowTestTest(cros_test_lib.MockTestCase,
424 api_config.ApiConfigMixin):
425 """Test the SimpleChromeWorkflowTest endpoint."""
426
427 @staticmethod
428 def _Output():
429 return test_pb2.SimpleChromeWorkflowTestResponse()
430
David Wellingc1433c22021-06-25 16:29:48 +0000431 def _Input(self,
432 sysroot_path=None,
433 build_target=None,
434 chrome_root=None,
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600435 goma_config=None):
436 proto = test_pb2.SimpleChromeWorkflowTestRequest()
437 if sysroot_path:
438 proto.sysroot.path = sysroot_path
439 if build_target:
440 proto.sysroot.build_target.name = build_target
441 if chrome_root:
442 proto.chrome_root = chrome_root
443 if goma_config:
444 proto.goma_config = goma_config
445 return proto
446
447 def setUp(self):
448 self.chrome_path = 'path/to/chrome'
449 self.sysroot_dir = 'build/board'
450 self.build_target = 'amd64'
451 self.mock_simple_chrome_workflow_test = self.PatchObject(
452 test_service, 'SimpleChromeWorkflowTest')
453
454 def testMissingBuildTarget(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700455 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600456 input_proto = self._Input(build_target=None, sysroot_path='/sysroot/dir',
457 chrome_root='/chrome/path')
458 with self.assertRaises(cros_build_lib.DieSystemExit):
459 test_controller.SimpleChromeWorkflowTest(input_proto, None,
460 self.api_config)
461
462 def testMissingSysrootPath(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700463 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600464 input_proto = self._Input(build_target='board', sysroot_path=None,
465 chrome_root='/chrome/path')
466 with self.assertRaises(cros_build_lib.DieSystemExit):
467 test_controller.SimpleChromeWorkflowTest(input_proto, None,
468 self.api_config)
469
470 def testMissingChromeRoot(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700471 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600472 input_proto = self._Input(build_target='board', sysroot_path='/sysroot/dir',
473 chrome_root=None)
474 with self.assertRaises(cros_build_lib.DieSystemExit):
475 test_controller.SimpleChromeWorkflowTest(input_proto, None,
476 self.api_config)
477
478 def testSimpleChromeWorkflowTest(self):
479 """Call SimpleChromeWorkflowTest with valid args and temp dir."""
480 request = self._Input(sysroot_path='sysroot_path', build_target='board',
481 chrome_root='/path/to/chrome')
482 response = self._Output()
483
484 test_controller.SimpleChromeWorkflowTest(request, response, self.api_config)
485 self.mock_simple_chrome_workflow_test.assert_called()
486
487 def testValidateOnly(self):
488 request = self._Input(sysroot_path='sysroot_path', build_target='board',
489 chrome_root='/path/to/chrome')
490 test_controller.SimpleChromeWorkflowTest(request, self._Output(),
491 self.validate_only_config)
492 self.mock_simple_chrome_workflow_test.assert_not_called()
493
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700494 def testMockCall(self):
495 """Test mock call does not execute any logic, returns success."""
496 patch = self.mock_simple_chrome_workflow_test = self.PatchObject(
497 test_service, 'SimpleChromeWorkflowTest')
498
499 request = self._Input(sysroot_path='sysroot_path', build_target='board',
500 chrome_root='/path/to/chrome')
501 rc = test_controller.SimpleChromeWorkflowTest(request, self._Output(),
502 self.mock_call_config)
503 patch.assert_not_called()
504 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
505
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600506
Alex Klein231d2da2019-07-22 16:44:45 -0600507class VmTestTest(cros_test_lib.RunCommandTestCase, api_config.ApiConfigMixin):
Evan Hernandez4e388a52019-05-01 12:16:33 -0600508 """Test the VmTest endpoint."""
509
510 def _GetInput(self, **kwargs):
511 values = dict(
512 build_target=common_pb2.BuildTarget(name='target'),
Alex Klein311b8022019-06-05 16:00:07 -0600513 vm_path=common_pb2.Path(path='/path/to/image.bin',
514 location=common_pb2.Path.INSIDE),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600515 test_harness=test_pb2.VmTestRequest.TAST,
516 vm_tests=[test_pb2.VmTestRequest.VmTest(pattern='suite')],
517 ssh_options=test_pb2.VmTestRequest.SshOptions(
Alex Klein231d2da2019-07-22 16:44:45 -0600518 port=1234, private_key_path={'path': '/path/to/id_rsa',
Alex Kleinaa705412019-06-04 15:00:30 -0600519 'location': common_pb2.Path.INSIDE}),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600520 )
521 values.update(kwargs)
522 return test_pb2.VmTestRequest(**values)
523
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700524 def _Output(self):
525 return test_pb2.VmTestResponse()
526
Alex Klein231d2da2019-07-22 16:44:45 -0600527 def testValidateOnly(self):
528 """Sanity check that a validate only call does not execute any logic."""
529 test_controller.VmTest(self._GetInput(), None, self.validate_only_config)
530 self.assertEqual(0, self.rc.call_count)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600531
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700532 def testMockCall(self):
533 """Test mock call does not execute any logic."""
534 patch = self.PatchObject(cros_build_lib, 'run')
535
536 request = self._GetInput()
537 response = self._Output()
538 # VmTest does not return a value, checking mocked value is flagged by lint.
539 test_controller.VmTest(request, response, self.mock_call_config)
540 patch.assert_not_called()
541
Evan Hernandez4e388a52019-05-01 12:16:33 -0600542 def testTastAllOptions(self):
543 """Test VmTest for Tast with all options set."""
Alex Klein231d2da2019-07-22 16:44:45 -0600544 test_controller.VmTest(self._GetInput(), None, self.api_config)
545 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700546 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600547 '--board', 'target',
548 '--image-path', '/path/to/image.bin',
549 '--tast', 'suite',
550 '--ssh-port', '1234',
551 '--private-key', '/path/to/id_rsa',
552 ])
553
554 def testAutotestAllOptions(self):
555 """Test VmTest for Autotest with all options set."""
556 input_proto = self._GetInput(test_harness=test_pb2.VmTestRequest.AUTOTEST)
Alex Klein231d2da2019-07-22 16:44:45 -0600557 test_controller.VmTest(input_proto, None, self.api_config)
558 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700559 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600560 '--board', 'target',
561 '--image-path', '/path/to/image.bin',
562 '--autotest', 'suite',
563 '--ssh-port', '1234',
564 '--private-key', '/path/to/id_rsa',
Greg Edelstondcb0e912020-08-31 11:09:40 -0600565 '--test_that-args=--allow-chrome-crashes',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600566 ])
567
568 def testMissingBuildTarget(self):
569 """Test VmTest dies when build_target not set."""
570 input_proto = self._GetInput(build_target=None)
571 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600572 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600573
574 def testMissingVmImage(self):
575 """Test VmTest dies when vm_image not set."""
Alex Klein311b8022019-06-05 16:00:07 -0600576 input_proto = self._GetInput(vm_path=None)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600577 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600578 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600579
580 def testMissingTestHarness(self):
581 """Test VmTest dies when test_harness not specified."""
582 input_proto = self._GetInput(
583 test_harness=test_pb2.VmTestRequest.UNSPECIFIED)
584 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600585 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600586
587 def testMissingVmTests(self):
588 """Test VmTest dies when vm_tests not set."""
589 input_proto = self._GetInput(vm_tests=[])
590 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600591 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600592
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700593 def testVmTest(self):
594 """Call VmTest with valid args and temp dir."""
595 request = self._GetInput()
596 response = self._Output()
597 patch = self.PatchObject(
598 cros_build_lib, 'run',
599 return_value=cros_build_lib.CommandResult(returncode=0))
600
601 test_controller.VmTest(request, response, self.api_config)
602 patch.assert_called()
603
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600604
Alex Klein231d2da2019-07-22 16:44:45 -0600605class MoblabVmTestTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600606 """Test the MoblabVmTest endpoint."""
607
608 @staticmethod
609 def _Payload(path):
610 return test_pb2.MoblabVmTestRequest.Payload(
611 path=common_pb2.Path(path=path))
612
613 @staticmethod
614 def _Output():
615 return test_pb2.MoblabVmTestResponse()
616
617 def _Input(self):
618 return test_pb2.MoblabVmTestRequest(
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600619 chroot=common_pb2.Chroot(path=self.chroot_dir),
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600620 image_payload=self._Payload(self.image_payload_dir),
621 cache_payloads=[self._Payload(self.autotest_payload_dir)])
622
623 def setUp(self):
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600624 self.chroot_dir = '/chroot'
625 self.chroot_tmp_dir = '/chroot/tmp'
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600626 self.image_payload_dir = '/payloads/image'
627 self.autotest_payload_dir = '/payloads/autotest'
628 self.builder = 'moblab-generic-vm/R12-3.4.5-67.890'
629 self.image_cache_dir = '/mnt/moblab/cache'
630 self.image_mount_dir = '/mnt/image'
631
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600632 self.PatchObject(chroot_lib.Chroot, 'tempdir', osutils.TempDir)
Evan Hernandez655e8042019-06-13 12:50:44 -0600633
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600634 self.mock_create_moblab_vms = self.PatchObject(
635 test_service, 'CreateMoblabVm')
636 self.mock_prepare_moblab_vm_image_cache = self.PatchObject(
637 test_service, 'PrepareMoblabVmImageCache',
638 return_value=self.image_cache_dir)
639 self.mock_run_moblab_vm_tests = self.PatchObject(
640 test_service, 'RunMoblabVmTest')
641 self.mock_validate_moblab_vm_tests = self.PatchObject(
642 test_service, 'ValidateMoblabVmTest')
643
644 @contextlib.contextmanager
Alex Klein38c7d9e2019-05-08 09:31:19 -0600645 def MockLoopbackPartitions(*_args, **_kwargs):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600646 mount = mock.MagicMock()
Evan Hernandez40ee7452019-06-13 12:51:43 -0600647 mount.Mount.return_value = [self.image_mount_dir]
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600648 yield mount
Alex Klein231d2da2019-07-22 16:44:45 -0600649
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600650 self.PatchObject(image_lib, 'LoopbackPartitions', MockLoopbackPartitions)
651
Alex Klein231d2da2019-07-22 16:44:45 -0600652 def testValidateOnly(self):
653 """Sanity check that a validate only call does not execute any logic."""
654 test_controller.MoblabVmTest(self._Input(), self._Output(),
655 self.validate_only_config)
656 self.mock_create_moblab_vms.assert_not_called()
657
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700658 def testMockCall(self):
659 """Test mock call does not execute any logic."""
660 patch = self.PatchObject(key_value_store, 'LoadFile')
661
662 # MoblabVmTest does not return a value, checking mocked value is flagged by
663 # lint.
664 test_controller.MoblabVmTest(self._Input(), self._Output(),
665 self.mock_call_config)
666 patch.assert_not_called()
667
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600668 def testImageContainsBuilder(self):
669 """MoblabVmTest calls service with correct args."""
670 request = self._Input()
671 response = self._Output()
672
673 self.PatchObject(
Mike Frysingere652ba12019-09-08 00:57:43 -0400674 key_value_store, 'LoadFile',
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600675 return_value={cros_set_lsb_release.LSB_KEY_BUILDER_PATH: self.builder})
676
Alex Klein231d2da2019-07-22 16:44:45 -0600677 test_controller.MoblabVmTest(request, response, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600678
679 self.assertEqual(
680 self.mock_create_moblab_vms.call_args_list,
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600681 [mock.call(mock.ANY, self.chroot_dir, self.image_payload_dir)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600682 self.assertEqual(
683 self.mock_prepare_moblab_vm_image_cache.call_args_list,
684 [mock.call(mock.ANY, self.builder, [self.autotest_payload_dir])])
685 self.assertEqual(
686 self.mock_run_moblab_vm_tests.call_args_list,
Evan Hernandez655e8042019-06-13 12:50:44 -0600687 [mock.call(mock.ANY, mock.ANY, self.builder, self.image_cache_dir,
688 mock.ANY)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600689 self.assertEqual(
690 self.mock_validate_moblab_vm_tests.call_args_list,
691 [mock.call(mock.ANY)])
692
693 def testImageMissingBuilder(self):
694 """MoblabVmTest dies when builder path not found in lsb-release."""
695 request = self._Input()
696 response = self._Output()
697
Mike Frysingere652ba12019-09-08 00:57:43 -0400698 self.PatchObject(key_value_store, 'LoadFile', return_value={})
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600699
700 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600701 test_controller.MoblabVmTest(request, response, self.api_config)
David Wellingc1433c22021-06-25 16:29:48 +0000702
703
704class GetArtifactsTest(cros_test_lib.MockTempDirTestCase):
705 """Test GetArtifacts."""
706
707 CODE_COVERAGE_LLVM_ARTIFACT_TYPE = (
708 common_pb2.ArtifactsByService.Test.ArtifactType.CODE_COVERAGE_LLVM_JSON
709 )
George Engelbrecht764b1cd2021-06-18 17:01:07 -0600710 UNIT_TEST_ARTIFACT_TYPE = (
711 common_pb2.ArtifactsByService.Test.ArtifactType.UNIT_TESTS
712 )
David Wellingc1433c22021-06-25 16:29:48 +0000713
714 def setUp(self):
715 """Set up the class for tests."""
716 chroot_dir = os.path.join(self.tempdir, 'chroot')
717 osutils.SafeMakedirs(chroot_dir)
718 osutils.SafeMakedirs(os.path.join(chroot_dir, 'tmp'))
719 self.chroot = chroot_lib.Chroot(chroot_dir)
720
721 sysroot_path = os.path.join(chroot_dir, 'build', 'board')
722 osutils.SafeMakedirs(sysroot_path)
723 self.sysroot = sysroot_lib.Sysroot(sysroot_path)
724
725 def testReturnsEmptyListWhenNoOutputArtifactsProvided(self):
726 """Test empty list is returned when there are no output_artifacts."""
727 result = test_controller.GetArtifacts(
728 common_pb2.ArtifactsByService.Test(output_artifacts=[]),
729 self.chroot, self.sysroot, self.tempdir)
730
731 self.assertEqual(len(result), 0)
732
733 def testShouldCallBundleCodeCoverageLlvmJsonForEachValidArtifact(self):
734 """Test BundleCodeCoverageLlvmJson is called on each valid artifact."""
735 BundleCodeCoverageLlvmJson_mock = self.PatchObject(
736 test_service, 'BundleCodeCoverageLlvmJson', return_value='test')
737
738 test_controller.GetArtifacts(
739 common_pb2.ArtifactsByService.Test(output_artifacts=[
740 # Valid
741 common_pb2.ArtifactsByService.Test.ArtifactInfo(
742 artifact_types=[
743 self.CODE_COVERAGE_LLVM_ARTIFACT_TYPE
744 ]
745 ),
746
747 # Invalid
748 common_pb2.ArtifactsByService.Test.ArtifactInfo(
749 artifact_types=[
750 common_pb2.ArtifactsByService.Test.ArtifactType.UNIT_TESTS
751 ]
752 ),
753 ]),
754 self.chroot, self.sysroot, self.tempdir)
755
756 BundleCodeCoverageLlvmJson_mock.assert_called_once()
757
758 def testShouldReturnValidResult(self):
759 """Test result contains paths and code_coverage_llvm_json type."""
760 self.PatchObject(test_service, 'BundleCodeCoverageLlvmJson',
761 return_value='test')
George Engelbrecht764b1cd2021-06-18 17:01:07 -0600762 self.PatchObject(test_service, 'BuildTargetUnitTestTarball',
763 return_value='unit_tests.tar')
David Wellingc1433c22021-06-25 16:29:48 +0000764
765 result = test_controller.GetArtifacts(
766 common_pb2.ArtifactsByService.Test(output_artifacts=[
767 # Valid
768 common_pb2.ArtifactsByService.Test.ArtifactInfo(
769 artifact_types=[
George Engelbrecht764b1cd2021-06-18 17:01:07 -0600770 self.UNIT_TEST_ARTIFACT_TYPE
771 ]
772 ),
773 common_pb2.ArtifactsByService.Test.ArtifactInfo(
774 artifact_types=[
David Wellingc1433c22021-06-25 16:29:48 +0000775 self.CODE_COVERAGE_LLVM_ARTIFACT_TYPE
776 ]
777 ),
778 ]),
779 self.chroot, self.sysroot, self.tempdir)
780
George Engelbrecht764b1cd2021-06-18 17:01:07 -0600781 self.assertEqual(result[0]['paths'], ['unit_tests.tar'])
782 self.assertEqual(result[0]['type'], self.UNIT_TEST_ARTIFACT_TYPE)
783 self.assertEqual(result[1]['paths'], ['test'])
784 self.assertEqual(result[1]['type'], self.CODE_COVERAGE_LLVM_ARTIFACT_TYPE)
Andrew Lamb763e3be2021-07-27 17:22:02 -0600785
786
787class GetCoverageRulesTest(cros_test_lib.RunCommandTempDirTestCase,
788 api_config.ApiConfigMixin):
789 """Tests for GetCoverageRules."""
790
Andrew Lambd814afa2021-08-11 11:04:20 -0600791 def _Input(self):
Andrew Lamb763e3be2021-07-27 17:22:02 -0600792 """Returns a sample GetCoverageRulesRequest for testing."""
Andrew Lambd814afa2021-08-11 11:04:20 -0600793 build_metadata_list_path = os.path.join(self.tempdir,
794 'build_metadata_list.jsonproto')
795 build_metadata_list = system_image_pb2.SystemImage.BuildMetadataList(
796 values=[
Andrew Lamb763e3be2021-07-27 17:22:02 -0600797 system_image_pb2.SystemImage.BuildMetadata(
798 build_target=system_image_pb2.SystemImage.BuildTarget(
799 portage_build_target=portage_pb2.Portage.BuildTarget(
800 overlay_name='overlayA')),
801 package_summary=system_image_pb2.SystemImage.BuildMetadata
802 .PackageSummary(
803 kernel=system_image_pb2.SystemImage.BuildMetadata.Kernel(
804 version='4.4')))
Andrew Lambd814afa2021-08-11 11:04:20 -0600805 ])
806 osutils.WriteFile(build_metadata_list_path,
807 json_format.MessageToJson(build_metadata_list))
808
809 dut_attribute_list_path = os.path.join(self.tempdir,
810 'dut_attribute_list.jsonproto')
811 dut_attribute_list = dut_attribute_pb2.DutAttributeList(dut_attributes=[
812 dut_attribute_pb2.DutAttribute(
813 id=dut_attribute_pb2.DutAttribute.Id(value='system_build_target'))
814 ])
815 osutils.WriteFile(dut_attribute_list_path,
816 json_format.MessageToJson(dut_attribute_list))
817
818 flat_config_list_path = os.path.join(self.tempdir,
819 'flat_config_list.jsonproto')
820 flat_config_list = flat_config_pb2.FlatConfigList(values=[
821 flat_config_pb2.FlatConfig(
822 hw_design=design_pb2.Design(
823 id=design_id_pb2.DesignId(value='design1')
824 )
825 )
826 ])
827 osutils.WriteFile(flat_config_list_path,
828 json_format.MessageToJson(flat_config_list))
829
830 return test_pb2.GetCoverageRulesRequest(
831 source_test_plans=[
832 source_test_plan_pb2.SourceTestPlan(
833 requirements=source_test_plan_pb2.SourceTestPlan.Requirements(
834 kernel_versions=source_test_plan_pb2.SourceTestPlan
835 .Requirements.KernelVersions()),
836 test_tags=['kernel']),
837 ],
838 build_metadata_list=common_pb2.Path(
839 path=build_metadata_list_path, location=common_pb2.Path.OUTSIDE),
840 dut_attribute_list=common_pb2.Path(
841 path=dut_attribute_list_path, location=common_pb2.Path.OUTSIDE),
842 flat_config_list=common_pb2.Path(
843 path=flat_config_list_path, location=common_pb2.Path.OUTSIDE),
844 )
Andrew Lamb763e3be2021-07-27 17:22:02 -0600845
846 @staticmethod
847 def _Output():
848 """Returns a sample GetCoverageRulesResponse for testing."""
849 return test_pb2.GetCoverageRulesResponse(coverage_rules=[
850 coverage_rule_pb2.CoverageRule(
851 name='kernel:4.4',
852 test_suites=[
853 test_suite_pb2.TestSuite(
854 test_case_tag_criteria=test_suite_pb2.TestSuite
855 .TestCaseTagCriteria(tags=['kernel']))
856 ],
857 dut_criteria=[
858 dut_attribute_pb2.DutCriterion(
859 attribute_id=dut_attribute_pb2.DutAttribute.Id(
860 value='system_build_target'),
861 values=['overlayA'],
862 )
863 ])
864 ])
865
866 @staticmethod
867 def _write_coverage_rules(path, coverage_rules):
868 """Write a list of CoverageRules in the same format as testplan."""
869 osutils.WriteFile(
870 path, '\n'.join(
871 json_format.MessageToJson(rule).replace('\n', '')
872 for rule in coverage_rules))
873
874 def testWritesInputsAndReturnsCoverageRules(self):
875 """Test inputs are written, and output of testplan is parsed."""
876 output_proto = test_pb2.GetCoverageRulesResponse()
877
878 self.rc.SetDefaultCmdResult(
879 side_effect=lambda _: self._write_coverage_rules(
880 os.path.join(self.tempdir, 'out.jsonpb'),
881 self._Output().coverage_rules))
882 self.PatchObject(osutils.TempDir, '__enter__', return_value=self.tempdir)
883
884 test_controller.GetCoverageRules(self._Input(), output_proto,
885 self.api_config)
886
Andrew Lamb763e3be2021-07-27 17:22:02 -0600887 self.assertEqual(output_proto, self._Output())