blob: 9c08098386c9ec4415b3945df4055ccbb59ee851 [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
Evan Hernandeze1e05d32019-07-19 12:32:18 -060016from chromite.lib import chroot_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060017from chromite.lib import cros_build_lib
18from chromite.lib import cros_test_lib
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060019from chromite.lib import image_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060020from chromite.lib import osutils
Alex Klein18a60af2020-06-11 12:08:47 -060021from chromite.lib.parser import package_info
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060022from chromite.scripts import cros_set_lsb_release
23from chromite.service import test as test_service
Mike Frysingere652ba12019-09-08 00:57:43 -040024from chromite.utils import key_value_store
Alex Kleina2e42c42019-04-17 16:13:19 -060025
26
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -070027class DebugInfoTestTest(cros_test_lib.MockTempDirTestCase,
28 api_config.ApiConfigMixin):
29 """Tests for the DebugInfoTest function."""
30
31 def setUp(self):
32 self.board = 'board'
33 self.chroot_path = os.path.join(self.tempdir, 'chroot')
34 self.sysroot_path = '/build/board'
35 self.full_sysroot_path = os.path.join(self.chroot_path,
36 self.sysroot_path.lstrip(os.sep))
37 osutils.SafeMakedirs(self.full_sysroot_path)
38
39 def _GetInput(self, sysroot_path=None, build_target=None):
40 """Helper to build an input message instance."""
41 proto = test_pb2.DebugInfoTestRequest()
42 if sysroot_path:
43 proto.sysroot.path = sysroot_path
44 if build_target:
45 proto.sysroot.build_target.name = build_target
46 return proto
47
48 def _GetOutput(self):
49 """Helper to get an empty output message instance."""
50 return test_pb2.DebugInfoTestResponse()
51
52 def testValidateOnly(self):
53 """Sanity check that a validate only call does not execute any logic."""
54 patch = self.PatchObject(test_service, 'DebugInfoTest')
55 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
56 test_controller.DebugInfoTest(input_msg, self._GetOutput(),
57 self.validate_only_config)
58 patch.assert_not_called()
59
Michael Mortensen85d38402019-12-12 09:50:29 -070060 def testMockError(self):
61 """Test mock error call does not execute any logic, returns error."""
62 patch = self.PatchObject(test_service, 'DebugInfoTest')
63
64 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
65 rc = test_controller.DebugInfoTest(input_msg, self._GetOutput(),
66 self.mock_error_config)
67 patch.assert_not_called()
68 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
69
70 def testMockCall(self):
71 """Test mock call does not execute any logic, returns success."""
72 patch = self.PatchObject(test_service, 'DebugInfoTest')
73
74 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
75 rc = test_controller.DebugInfoTest(input_msg, self._GetOutput(),
76 self.mock_call_config)
77 patch.assert_not_called()
78 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
79
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -070080 def testNoBuildTargetNoSysrootFails(self):
81 """Test missing build target name and sysroot path fails."""
82 input_msg = self._GetInput()
83 output_msg = self._GetOutput()
84 with self.assertRaises(cros_build_lib.DieSystemExit):
85 test_controller.DebugInfoTest(input_msg, output_msg, self.api_config)
86
87 def testDebugInfoTest(self):
88 """Call DebugInfoTest with valid sysroot_path."""
89 request = self._GetInput(sysroot_path=self.full_sysroot_path)
90
91 test_controller.DebugInfoTest(request, self._GetOutput(), self.api_config)
92
93
Alex Klein231d2da2019-07-22 16:44:45 -060094class BuildTargetUnitTestTest(cros_test_lib.MockTempDirTestCase,
95 api_config.ApiConfigMixin):
Alex Kleina2e42c42019-04-17 16:13:19 -060096 """Tests for the UnitTest function."""
97
Navil Perezc0b29a82020-07-07 14:17:48 +000098 def _GetInput(self,
99 board=None,
100 result_path=None,
101 chroot_path=None,
102 cache_dir=None,
103 empty_sysroot=None,
104 packages=None,
Alex Kleinb64e5f82020-09-23 10:55:31 -0600105 blocklist=None):
Alex Kleina2e42c42019-04-17 16:13:19 -0600106 """Helper to build an input message instance."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000107 formatted_packages = []
108 for pkg in packages or []:
109 formatted_packages.append({
110 'category': pkg.category,
111 'package_name': pkg.package
112 })
Alex Kleinb64e5f82020-09-23 10:55:31 -0600113 formatted_blocklist = []
114 for pkg in blocklist or []:
115 formatted_blocklist.append({'category': pkg.category,
Alex Kleinf2674462019-05-16 16:47:24 -0600116 'package_name': pkg.package})
117
Alex Kleina2e42c42019-04-17 16:13:19 -0600118 return test_pb2.BuildTargetUnitTestRequest(
119 build_target={'name': board}, result_path=result_path,
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600120 chroot={'path': chroot_path, 'cache_dir': cache_dir},
Alex Kleinf2674462019-05-16 16:47:24 -0600121 flags={'empty_sysroot': empty_sysroot},
Alex Klein64ac34c2020-09-23 10:21:33 -0600122 packages=formatted_packages,
Alex Kleinb64e5f82020-09-23 10:55:31 -0600123 package_blacklist=formatted_blocklist,
Alex Kleina2e42c42019-04-17 16:13:19 -0600124 )
125
126 def _GetOutput(self):
127 """Helper to get an empty output message instance."""
128 return test_pb2.BuildTargetUnitTestResponse()
129
Alex Klein231d2da2019-07-22 16:44:45 -0600130 def testValidateOnly(self):
131 """Sanity check that a validate only call does not execute any logic."""
132 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
133
134 input_msg = self._GetInput(board='board', result_path=self.tempdir)
135 test_controller.BuildTargetUnitTest(input_msg, self._GetOutput(),
136 self.validate_only_config)
137 patch.assert_not_called()
138
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700139 def testMockCall(self):
140 """Test that a mock call does not execute logic, returns mocked value."""
141 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
142
143 input_msg = self._GetInput(board='board', result_path=self.tempdir)
144 response = self._GetOutput()
145 test_controller.BuildTargetUnitTest(input_msg, response,
146 self.mock_call_config)
147 patch.assert_not_called()
148 self.assertEqual(response.tarball_path,
149 os.path.join(input_msg.result_path, 'unit_tests.tar'))
150
151 def testMockError(self):
Michael Mortensen85d38402019-12-12 09:50:29 -0700152 """Test that a mock error does not execute logic, returns error."""
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700153 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
154
155 input_msg = self._GetInput(board='board', result_path=self.tempdir)
156 response = self._GetOutput()
157 rc = test_controller.BuildTargetUnitTest(input_msg, response,
158 self.mock_error_config)
159 patch.assert_not_called()
160 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
161 self.assertTrue(response.failed_packages)
162 self.assertEqual(response.failed_packages[0].category, 'foo')
163 self.assertEqual(response.failed_packages[0].package_name, 'bar')
164 self.assertEqual(response.failed_packages[1].category, 'cat')
165 self.assertEqual(response.failed_packages[1].package_name, 'pkg')
166
Alex Kleina2e42c42019-04-17 16:13:19 -0600167 def testNoArgumentFails(self):
168 """Test no arguments fails."""
169 input_msg = self._GetInput()
170 output_msg = self._GetOutput()
171 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600172 test_controller.BuildTargetUnitTest(input_msg, output_msg,
173 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600174
175 def testNoBuildTargetFails(self):
176 """Test missing build target name fails."""
177 input_msg = self._GetInput(result_path=self.tempdir)
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 testNoResultPathFails(self):
184 """Test missing result path fails."""
185 # Missing result_path.
186 input_msg = self._GetInput(board='board')
187 output_msg = self._GetOutput()
188 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600189 test_controller.BuildTargetUnitTest(input_msg, output_msg,
190 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600191
Alex Klein64ac34c2020-09-23 10:21:33 -0600192 def testInvalidPackageFails(self):
193 """Test missing result path fails."""
194 # Missing result_path.
195 pkg = package_info.PackageInfo(package='bar')
196 input_msg = self._GetInput(board='board', result_path=self.tempdir,
197 packages=[pkg])
198 output_msg = self._GetOutput()
199 with self.assertRaises(cros_build_lib.DieSystemExit):
200 test_controller.BuildTargetUnitTest(input_msg, output_msg,
201 self.api_config)
202
Alex Kleina2e42c42019-04-17 16:13:19 -0600203 def testPackageBuildFailure(self):
204 """Test handling of raised BuildPackageFailure."""
205 tempdir = osutils.TempDir(base_dir=self.tempdir)
206 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
207
208 pkgs = ['cat/pkg', 'foo/bar']
209 expected = [('cat', 'pkg'), ('foo', 'bar')]
Alex Kleina2e42c42019-04-17 16:13:19 -0600210
Alex Klein38c7d9e2019-05-08 09:31:19 -0600211 result = test_service.BuildTargetUnitTestResult(1, None)
Alex Klein18a60af2020-06-11 12:08:47 -0600212 result.failed_cpvs = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Klein38c7d9e2019-05-08 09:31:19 -0600213 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600214
215 input_msg = self._GetInput(board='board', result_path=self.tempdir)
216 output_msg = self._GetOutput()
217
Alex Klein231d2da2019-07-22 16:44:45 -0600218 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
219 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600220
Alex Klein8cb365a2019-05-15 16:24:53 -0600221 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600222 self.assertTrue(output_msg.failed_packages)
223 failed = []
224 for pi in output_msg.failed_packages:
225 failed.append((pi.category, pi.package_name))
Mike Frysinger678735c2019-09-28 18:23:28 -0400226 self.assertCountEqual(expected, failed)
Alex Kleina2e42c42019-04-17 16:13:19 -0600227
228 def testOtherBuildScriptFailure(self):
229 """Test build script failure due to non-package emerge error."""
230 tempdir = osutils.TempDir(base_dir=self.tempdir)
231 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
232
Alex Klein38c7d9e2019-05-08 09:31:19 -0600233 result = test_service.BuildTargetUnitTestResult(1, None)
234 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600235
Alex Kleinf2674462019-05-16 16:47:24 -0600236 pkgs = ['foo/bar', 'cat/pkg']
Alex Kleinb64e5f82020-09-23 10:55:31 -0600237 blocklist = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600238 input_msg = self._GetInput(board='board', result_path=self.tempdir,
Alex Kleinb64e5f82020-09-23 10:55:31 -0600239 empty_sysroot=True, blocklist=blocklist)
Alex Kleina2e42c42019-04-17 16:13:19 -0600240 output_msg = self._GetOutput()
241
Alex Klein231d2da2019-07-22 16:44:45 -0600242 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
243 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600244
Alex Klein8cb365a2019-05-15 16:24:53 -0600245 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600246 self.assertFalse(output_msg.failed_packages)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600247
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700248 def testBuildTargetUnitTest(self):
249 """Test BuildTargetUnitTest successful call."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000250 pkgs = ['foo/bar', 'cat/pkg']
Alex Klein18a60af2020-06-11 12:08:47 -0600251 packages = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Navil Perezc0b29a82020-07-07 14:17:48 +0000252 input_msg = self._GetInput(
253 board='board', result_path=self.tempdir, packages=packages)
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700254
255 result = test_service.BuildTargetUnitTestResult(0, None)
256 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
257
258 tarball_result = os.path.join(input_msg.result_path, 'unit_tests.tar')
259 self.PatchObject(test_service, 'BuildTargetUnitTestTarball',
260 return_value=tarball_result)
261
262 response = self._GetOutput()
263 test_controller.BuildTargetUnitTest(input_msg, response,
264 self.api_config)
265 self.assertEqual(response.tarball_path,
266 os.path.join(input_msg.result_path, 'unit_tests.tar'))
267
Evan Hernandez4e388a52019-05-01 12:16:33 -0600268
C Shapiro91af1ce2021-06-17 12:42:09 -0500269class BuildTestServiceContainers(cros_test_lib.MockTestCase,
270 api_config.ApiConfigMixin):
271 """Tests for the BuildTestServiceContainers function."""
272
273 def setUp(self):
274 self.request = test_pb2.BuildTestServiceContainersRequest(
275 chroot={'path': '/path/to/chroot'},
276 build_target={'name': 'build_target'},
277 version = 'R93-14033.0.0',
278 )
279
280
281 def testSuccess(self):
282 """Check passing case with mocked cros_build_lib.run."""
283 patch = self.PatchObject(
284 cros_build_lib, 'run',
285 return_value=cros_build_lib.CommandResult(returncode=0))
286
287 response = test_pb2.BuildTestServiceContainersResponse()
288 test_controller.BuildTestServiceContainers(
289 self.request,
290 response,
291 self.api_config)
292 patch.assert_called()
293 for result in response.results:
294 self.assertEqual(result.WhichOneof('result'), 'success')
295
296
297 def testFailure(self):
298 """Check failure case with mocked cros_build_lib.run."""
299 patch = self.PatchObject(
300 cros_build_lib, 'run',
301 return_value=cros_build_lib.CommandResult(returncode=1))
302
303 response = test_pb2.BuildTestServiceContainersResponse()
304 test_controller.BuildTestServiceContainers(
305 self.request,
306 response,
307 self.api_config)
308 patch.assert_called()
309 for result in response.results:
310 self.assertEqual(result.WhichOneof('result'), 'failure')
311
312
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700313class ChromiteUnitTestTest(cros_test_lib.MockTestCase,
314 api_config.ApiConfigMixin):
315 """Tests for the ChromiteInfoTest function."""
316
317 def setUp(self):
318 self.board = 'board'
319 self.chroot_path = '/path/to/chroot'
320
321 def _GetInput(self, chroot_path=None):
322 """Helper to build an input message instance."""
323 proto = test_pb2.ChromiteUnitTestRequest(
324 chroot={'path': chroot_path},
325 )
326 return proto
327
328 def _GetOutput(self):
329 """Helper to get an empty output message instance."""
330 return test_pb2.ChromiteUnitTestResponse()
331
332 def testValidateOnly(self):
333 """Sanity check that a validate only call does not execute any logic."""
334 patch = self.PatchObject(cros_build_lib, 'run')
335
336 input_msg = self._GetInput(chroot_path=self.chroot_path)
337 test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
338 self.validate_only_config)
339 patch.assert_not_called()
340
Michael Mortensen7a860eb2019-12-03 20:25:15 -0700341 def testMockError(self):
342 """Test mock error call does not execute any logic, returns error."""
343 patch = self.PatchObject(cros_build_lib, 'run')
344
345 input_msg = self._GetInput(chroot_path=self.chroot_path)
346 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
347 self.mock_error_config)
348 patch.assert_not_called()
349 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
350
351 def testMockCall(self):
352 """Test mock call does not execute any logic, returns success."""
353 patch = self.PatchObject(cros_build_lib, 'run')
354
355 input_msg = self._GetInput(chroot_path=self.chroot_path)
356 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
357 self.mock_call_config)
358 patch.assert_not_called()
359 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
360
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700361 def testChromiteUnitTest(self):
362 """Call ChromiteUnitTest with mocked cros_build_lib.run."""
363 request = self._GetInput(chroot_path=self.chroot_path)
364 patch = self.PatchObject(
365 cros_build_lib, 'run',
366 return_value=cros_build_lib.CommandResult(returncode=0))
367
368 test_controller.ChromiteUnitTest(request, self._GetOutput(),
369 self.api_config)
370 patch.assert_called_once()
371
372
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600373class CrosSigningTestTest(cros_test_lib.RunCommandTestCase,
374 api_config.ApiConfigMixin):
375 """CrosSigningTest tests."""
376
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700377 def setUp(self):
378 self.chroot_path = '/path/to/chroot'
379
380 def _GetInput(self, chroot_path=None):
381 """Helper to build an input message instance."""
382 proto = test_pb2.CrosSigningTestRequest(
383 chroot={'path': chroot_path},
384 )
385 return proto
386
387 def _GetOutput(self):
388 """Helper to get an empty output message instance."""
389 return test_pb2.CrosSigningTestResponse()
390
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600391 def testValidateOnly(self):
392 """Sanity check that a validate only call does not execute any logic."""
393 test_controller.CrosSigningTest(None, None, self.validate_only_config)
394 self.assertFalse(self.rc.call_count)
395
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700396 def testMockCall(self):
397 """Test mock call does not execute any logic, returns success."""
398 rc = test_controller.CrosSigningTest(None, None, self.mock_call_config)
399 self.assertFalse(self.rc.call_count)
400 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
401
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700402 def testCrosSigningTest(self):
403 """Call CrosSigningTest with mocked cros_build_lib.run."""
404 request = self._GetInput(chroot_path=self.chroot_path)
405 patch = self.PatchObject(
406 cros_build_lib, 'run',
407 return_value=cros_build_lib.CommandResult(returncode=0))
408
409 test_controller.CrosSigningTest(request, self._GetOutput(),
410 self.api_config)
411 patch.assert_called_once()
412
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600413
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600414class SimpleChromeWorkflowTestTest(cros_test_lib.MockTestCase,
415 api_config.ApiConfigMixin):
416 """Test the SimpleChromeWorkflowTest endpoint."""
417
418 @staticmethod
419 def _Output():
420 return test_pb2.SimpleChromeWorkflowTestResponse()
421
422 def _Input(self, sysroot_path=None, build_target=None, chrome_root=None,
423 goma_config=None):
424 proto = test_pb2.SimpleChromeWorkflowTestRequest()
425 if sysroot_path:
426 proto.sysroot.path = sysroot_path
427 if build_target:
428 proto.sysroot.build_target.name = build_target
429 if chrome_root:
430 proto.chrome_root = chrome_root
431 if goma_config:
432 proto.goma_config = goma_config
433 return proto
434
435 def setUp(self):
436 self.chrome_path = 'path/to/chrome'
437 self.sysroot_dir = 'build/board'
438 self.build_target = 'amd64'
439 self.mock_simple_chrome_workflow_test = self.PatchObject(
440 test_service, 'SimpleChromeWorkflowTest')
441
442 def testMissingBuildTarget(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700443 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600444 input_proto = self._Input(build_target=None, sysroot_path='/sysroot/dir',
445 chrome_root='/chrome/path')
446 with self.assertRaises(cros_build_lib.DieSystemExit):
447 test_controller.SimpleChromeWorkflowTest(input_proto, None,
448 self.api_config)
449
450 def testMissingSysrootPath(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700451 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600452 input_proto = self._Input(build_target='board', sysroot_path=None,
453 chrome_root='/chrome/path')
454 with self.assertRaises(cros_build_lib.DieSystemExit):
455 test_controller.SimpleChromeWorkflowTest(input_proto, None,
456 self.api_config)
457
458 def testMissingChromeRoot(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700459 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600460 input_proto = self._Input(build_target='board', sysroot_path='/sysroot/dir',
461 chrome_root=None)
462 with self.assertRaises(cros_build_lib.DieSystemExit):
463 test_controller.SimpleChromeWorkflowTest(input_proto, None,
464 self.api_config)
465
466 def testSimpleChromeWorkflowTest(self):
467 """Call SimpleChromeWorkflowTest with valid args and temp dir."""
468 request = self._Input(sysroot_path='sysroot_path', build_target='board',
469 chrome_root='/path/to/chrome')
470 response = self._Output()
471
472 test_controller.SimpleChromeWorkflowTest(request, response, self.api_config)
473 self.mock_simple_chrome_workflow_test.assert_called()
474
475 def testValidateOnly(self):
476 request = self._Input(sysroot_path='sysroot_path', build_target='board',
477 chrome_root='/path/to/chrome')
478 test_controller.SimpleChromeWorkflowTest(request, self._Output(),
479 self.validate_only_config)
480 self.mock_simple_chrome_workflow_test.assert_not_called()
481
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700482 def testMockCall(self):
483 """Test mock call does not execute any logic, returns success."""
484 patch = self.mock_simple_chrome_workflow_test = self.PatchObject(
485 test_service, 'SimpleChromeWorkflowTest')
486
487 request = self._Input(sysroot_path='sysroot_path', build_target='board',
488 chrome_root='/path/to/chrome')
489 rc = test_controller.SimpleChromeWorkflowTest(request, self._Output(),
490 self.mock_call_config)
491 patch.assert_not_called()
492 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
493
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600494
Alex Klein231d2da2019-07-22 16:44:45 -0600495class VmTestTest(cros_test_lib.RunCommandTestCase, api_config.ApiConfigMixin):
Evan Hernandez4e388a52019-05-01 12:16:33 -0600496 """Test the VmTest endpoint."""
497
498 def _GetInput(self, **kwargs):
499 values = dict(
500 build_target=common_pb2.BuildTarget(name='target'),
Alex Klein311b8022019-06-05 16:00:07 -0600501 vm_path=common_pb2.Path(path='/path/to/image.bin',
502 location=common_pb2.Path.INSIDE),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600503 test_harness=test_pb2.VmTestRequest.TAST,
504 vm_tests=[test_pb2.VmTestRequest.VmTest(pattern='suite')],
505 ssh_options=test_pb2.VmTestRequest.SshOptions(
Alex Klein231d2da2019-07-22 16:44:45 -0600506 port=1234, private_key_path={'path': '/path/to/id_rsa',
Alex Kleinaa705412019-06-04 15:00:30 -0600507 'location': common_pb2.Path.INSIDE}),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600508 )
509 values.update(kwargs)
510 return test_pb2.VmTestRequest(**values)
511
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700512 def _Output(self):
513 return test_pb2.VmTestResponse()
514
Alex Klein231d2da2019-07-22 16:44:45 -0600515 def testValidateOnly(self):
516 """Sanity check that a validate only call does not execute any logic."""
517 test_controller.VmTest(self._GetInput(), None, self.validate_only_config)
518 self.assertEqual(0, self.rc.call_count)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600519
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700520 def testMockCall(self):
521 """Test mock call does not execute any logic."""
522 patch = self.PatchObject(cros_build_lib, 'run')
523
524 request = self._GetInput()
525 response = self._Output()
526 # VmTest does not return a value, checking mocked value is flagged by lint.
527 test_controller.VmTest(request, response, self.mock_call_config)
528 patch.assert_not_called()
529
Evan Hernandez4e388a52019-05-01 12:16:33 -0600530 def testTastAllOptions(self):
531 """Test VmTest for Tast with all options set."""
Alex Klein231d2da2019-07-22 16:44:45 -0600532 test_controller.VmTest(self._GetInput(), None, self.api_config)
533 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700534 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600535 '--board', 'target',
536 '--image-path', '/path/to/image.bin',
537 '--tast', 'suite',
538 '--ssh-port', '1234',
539 '--private-key', '/path/to/id_rsa',
540 ])
541
542 def testAutotestAllOptions(self):
543 """Test VmTest for Autotest with all options set."""
544 input_proto = self._GetInput(test_harness=test_pb2.VmTestRequest.AUTOTEST)
Alex Klein231d2da2019-07-22 16:44:45 -0600545 test_controller.VmTest(input_proto, None, self.api_config)
546 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700547 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600548 '--board', 'target',
549 '--image-path', '/path/to/image.bin',
550 '--autotest', 'suite',
551 '--ssh-port', '1234',
552 '--private-key', '/path/to/id_rsa',
Greg Edelstondcb0e912020-08-31 11:09:40 -0600553 '--test_that-args=--allow-chrome-crashes',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600554 ])
555
556 def testMissingBuildTarget(self):
557 """Test VmTest dies when build_target not set."""
558 input_proto = self._GetInput(build_target=None)
559 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600560 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600561
562 def testMissingVmImage(self):
563 """Test VmTest dies when vm_image not set."""
Alex Klein311b8022019-06-05 16:00:07 -0600564 input_proto = self._GetInput(vm_path=None)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600565 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600566 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600567
568 def testMissingTestHarness(self):
569 """Test VmTest dies when test_harness not specified."""
570 input_proto = self._GetInput(
571 test_harness=test_pb2.VmTestRequest.UNSPECIFIED)
572 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600573 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600574
575 def testMissingVmTests(self):
576 """Test VmTest dies when vm_tests not set."""
577 input_proto = self._GetInput(vm_tests=[])
578 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600579 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600580
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700581 def testVmTest(self):
582 """Call VmTest with valid args and temp dir."""
583 request = self._GetInput()
584 response = self._Output()
585 patch = self.PatchObject(
586 cros_build_lib, 'run',
587 return_value=cros_build_lib.CommandResult(returncode=0))
588
589 test_controller.VmTest(request, response, self.api_config)
590 patch.assert_called()
591
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600592
Alex Klein231d2da2019-07-22 16:44:45 -0600593class MoblabVmTestTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600594 """Test the MoblabVmTest endpoint."""
595
596 @staticmethod
597 def _Payload(path):
598 return test_pb2.MoblabVmTestRequest.Payload(
599 path=common_pb2.Path(path=path))
600
601 @staticmethod
602 def _Output():
603 return test_pb2.MoblabVmTestResponse()
604
605 def _Input(self):
606 return test_pb2.MoblabVmTestRequest(
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600607 chroot=common_pb2.Chroot(path=self.chroot_dir),
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600608 image_payload=self._Payload(self.image_payload_dir),
609 cache_payloads=[self._Payload(self.autotest_payload_dir)])
610
611 def setUp(self):
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600612 self.chroot_dir = '/chroot'
613 self.chroot_tmp_dir = '/chroot/tmp'
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600614 self.image_payload_dir = '/payloads/image'
615 self.autotest_payload_dir = '/payloads/autotest'
616 self.builder = 'moblab-generic-vm/R12-3.4.5-67.890'
617 self.image_cache_dir = '/mnt/moblab/cache'
618 self.image_mount_dir = '/mnt/image'
619
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600620 self.PatchObject(chroot_lib.Chroot, 'tempdir', osutils.TempDir)
Evan Hernandez655e8042019-06-13 12:50:44 -0600621
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600622 self.mock_create_moblab_vms = self.PatchObject(
623 test_service, 'CreateMoblabVm')
624 self.mock_prepare_moblab_vm_image_cache = self.PatchObject(
625 test_service, 'PrepareMoblabVmImageCache',
626 return_value=self.image_cache_dir)
627 self.mock_run_moblab_vm_tests = self.PatchObject(
628 test_service, 'RunMoblabVmTest')
629 self.mock_validate_moblab_vm_tests = self.PatchObject(
630 test_service, 'ValidateMoblabVmTest')
631
632 @contextlib.contextmanager
Alex Klein38c7d9e2019-05-08 09:31:19 -0600633 def MockLoopbackPartitions(*_args, **_kwargs):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600634 mount = mock.MagicMock()
Evan Hernandez40ee7452019-06-13 12:51:43 -0600635 mount.Mount.return_value = [self.image_mount_dir]
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600636 yield mount
Alex Klein231d2da2019-07-22 16:44:45 -0600637
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600638 self.PatchObject(image_lib, 'LoopbackPartitions', MockLoopbackPartitions)
639
Alex Klein231d2da2019-07-22 16:44:45 -0600640 def testValidateOnly(self):
641 """Sanity check that a validate only call does not execute any logic."""
642 test_controller.MoblabVmTest(self._Input(), self._Output(),
643 self.validate_only_config)
644 self.mock_create_moblab_vms.assert_not_called()
645
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700646 def testMockCall(self):
647 """Test mock call does not execute any logic."""
648 patch = self.PatchObject(key_value_store, 'LoadFile')
649
650 # MoblabVmTest does not return a value, checking mocked value is flagged by
651 # lint.
652 test_controller.MoblabVmTest(self._Input(), self._Output(),
653 self.mock_call_config)
654 patch.assert_not_called()
655
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600656 def testImageContainsBuilder(self):
657 """MoblabVmTest calls service with correct args."""
658 request = self._Input()
659 response = self._Output()
660
661 self.PatchObject(
Mike Frysingere652ba12019-09-08 00:57:43 -0400662 key_value_store, 'LoadFile',
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600663 return_value={cros_set_lsb_release.LSB_KEY_BUILDER_PATH: self.builder})
664
Alex Klein231d2da2019-07-22 16:44:45 -0600665 test_controller.MoblabVmTest(request, response, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600666
667 self.assertEqual(
668 self.mock_create_moblab_vms.call_args_list,
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600669 [mock.call(mock.ANY, self.chroot_dir, self.image_payload_dir)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600670 self.assertEqual(
671 self.mock_prepare_moblab_vm_image_cache.call_args_list,
672 [mock.call(mock.ANY, self.builder, [self.autotest_payload_dir])])
673 self.assertEqual(
674 self.mock_run_moblab_vm_tests.call_args_list,
Evan Hernandez655e8042019-06-13 12:50:44 -0600675 [mock.call(mock.ANY, mock.ANY, self.builder, self.image_cache_dir,
676 mock.ANY)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600677 self.assertEqual(
678 self.mock_validate_moblab_vm_tests.call_args_list,
679 [mock.call(mock.ANY)])
680
681 def testImageMissingBuilder(self):
682 """MoblabVmTest dies when builder path not found in lsb-release."""
683 request = self._Input()
684 response = self._Output()
685
Mike Frysingere652ba12019-09-08 00:57:43 -0400686 self.PatchObject(key_value_store, 'LoadFile', return_value={})
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600687
688 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600689 test_controller.MoblabVmTest(request, response, self.api_config)