blob: b0a36dc346509a41530431396b6684836942da78 [file] [log] [blame]
Alex Kleina2e42c42019-04-17 16:13:19 -06001# -*- coding: utf-8 -*-
2# Copyright 2019 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""The test controller tests."""
7
8from __future__ import print_function
9
Alex Klein9f915782020-02-14 23:15:09 +000010import contextlib
Mike Frysingeref94e4c2020-02-10 23:59:54 -050011import os
12import sys
13
Alex Kleinfa6ebdc2019-05-10 10:57:31 -060014import mock
15
Alex Klein231d2da2019-07-22 16:44:45 -060016from chromite.api import api_config
Alex Klein8cb365a2019-05-15 16:24:53 -060017from chromite.api import controller
Alex Kleina2e42c42019-04-17 16:13:19 -060018from chromite.api.controller import test as test_controller
Evan Hernandez4e388a52019-05-01 12:16:33 -060019from chromite.api.gen.chromiumos import common_pb2
Alex Kleina2e42c42019-04-17 16:13:19 -060020from chromite.api.gen.chromite.api import test_pb2
Evan Hernandeze1e05d32019-07-19 12:32:18 -060021from chromite.lib import chroot_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060022from chromite.lib import cros_build_lib
23from chromite.lib import cros_test_lib
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060024from chromite.lib import image_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060025from chromite.lib import osutils
26from chromite.lib import portage_util
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060027from chromite.scripts import cros_set_lsb_release
28from chromite.service import test as test_service
Mike Frysingere652ba12019-09-08 00:57:43 -040029from chromite.utils import key_value_store
Alex Kleina2e42c42019-04-17 16:13:19 -060030
31
Mike Frysingeref94e4c2020-02-10 23:59:54 -050032assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
33
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
106 def _GetInput(self, board=None, result_path=None, chroot_path=None,
Alex Kleinf2674462019-05-16 16:47:24 -0600107 cache_dir=None, empty_sysroot=None, blacklist=None):
Alex Kleina2e42c42019-04-17 16:13:19 -0600108 """Helper to build an input message instance."""
Alex Kleinf2674462019-05-16 16:47:24 -0600109 formatted_blacklist = []
110 for pkg in blacklist or []:
111 formatted_blacklist.append({'category': pkg.category,
112 'package_name': pkg.package})
113
Alex Kleina2e42c42019-04-17 16:13:19 -0600114 return test_pb2.BuildTargetUnitTestRequest(
115 build_target={'name': board}, result_path=result_path,
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600116 chroot={'path': chroot_path, 'cache_dir': cache_dir},
Alex Kleinf2674462019-05-16 16:47:24 -0600117 flags={'empty_sysroot': empty_sysroot},
118 package_blacklist=formatted_blacklist,
Alex Kleina2e42c42019-04-17 16:13:19 -0600119 )
120
121 def _GetOutput(self):
122 """Helper to get an empty output message instance."""
123 return test_pb2.BuildTargetUnitTestResponse()
124
Alex Klein231d2da2019-07-22 16:44:45 -0600125 def testValidateOnly(self):
126 """Sanity check that a validate only call does not execute any logic."""
127 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
128
129 input_msg = self._GetInput(board='board', result_path=self.tempdir)
130 test_controller.BuildTargetUnitTest(input_msg, self._GetOutput(),
131 self.validate_only_config)
132 patch.assert_not_called()
133
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700134 def testMockCall(self):
135 """Test that a mock call does not execute logic, returns mocked value."""
136 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
137
138 input_msg = self._GetInput(board='board', result_path=self.tempdir)
139 response = self._GetOutput()
140 test_controller.BuildTargetUnitTest(input_msg, response,
141 self.mock_call_config)
142 patch.assert_not_called()
143 self.assertEqual(response.tarball_path,
144 os.path.join(input_msg.result_path, 'unit_tests.tar'))
145
146 def testMockError(self):
Michael Mortensen85d38402019-12-12 09:50:29 -0700147 """Test that a mock error does not execute logic, returns error."""
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700148 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
149
150 input_msg = self._GetInput(board='board', result_path=self.tempdir)
151 response = self._GetOutput()
152 rc = test_controller.BuildTargetUnitTest(input_msg, response,
153 self.mock_error_config)
154 patch.assert_not_called()
155 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
156 self.assertTrue(response.failed_packages)
157 self.assertEqual(response.failed_packages[0].category, 'foo')
158 self.assertEqual(response.failed_packages[0].package_name, 'bar')
159 self.assertEqual(response.failed_packages[1].category, 'cat')
160 self.assertEqual(response.failed_packages[1].package_name, 'pkg')
161
Alex Kleina2e42c42019-04-17 16:13:19 -0600162 def testNoArgumentFails(self):
163 """Test no arguments fails."""
164 input_msg = self._GetInput()
165 output_msg = self._GetOutput()
166 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600167 test_controller.BuildTargetUnitTest(input_msg, output_msg,
168 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600169
170 def testNoBuildTargetFails(self):
171 """Test missing build target name fails."""
172 input_msg = self._GetInput(result_path=self.tempdir)
173 output_msg = self._GetOutput()
174 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600175 test_controller.BuildTargetUnitTest(input_msg, output_msg,
176 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600177
178 def testNoResultPathFails(self):
179 """Test missing result path fails."""
180 # Missing result_path.
181 input_msg = self._GetInput(board='board')
182 output_msg = self._GetOutput()
183 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600184 test_controller.BuildTargetUnitTest(input_msg, output_msg,
185 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600186
187 def testPackageBuildFailure(self):
188 """Test handling of raised BuildPackageFailure."""
189 tempdir = osutils.TempDir(base_dir=self.tempdir)
190 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
191
192 pkgs = ['cat/pkg', 'foo/bar']
193 expected = [('cat', 'pkg'), ('foo', 'bar')]
Alex Kleina2e42c42019-04-17 16:13:19 -0600194
Alex Klein38c7d9e2019-05-08 09:31:19 -0600195 result = test_service.BuildTargetUnitTestResult(1, None)
196 result.failed_cpvs = [portage_util.SplitCPV(p, strict=False) for p in pkgs]
197 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600198
199 input_msg = self._GetInput(board='board', result_path=self.tempdir)
200 output_msg = self._GetOutput()
201
Alex Klein231d2da2019-07-22 16:44:45 -0600202 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
203 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600204
Alex Klein8cb365a2019-05-15 16:24:53 -0600205 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600206 self.assertTrue(output_msg.failed_packages)
207 failed = []
208 for pi in output_msg.failed_packages:
209 failed.append((pi.category, pi.package_name))
Mike Frysinger678735c2019-09-28 18:23:28 -0400210 self.assertCountEqual(expected, failed)
Alex Kleina2e42c42019-04-17 16:13:19 -0600211
212 def testOtherBuildScriptFailure(self):
213 """Test build script failure due to non-package emerge error."""
214 tempdir = osutils.TempDir(base_dir=self.tempdir)
215 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
216
Alex Klein38c7d9e2019-05-08 09:31:19 -0600217 result = test_service.BuildTargetUnitTestResult(1, None)
218 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600219
Alex Kleinf2674462019-05-16 16:47:24 -0600220 pkgs = ['foo/bar', 'cat/pkg']
221 blacklist = [portage_util.SplitCPV(p, strict=False) for p in pkgs]
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600222 input_msg = self._GetInput(board='board', result_path=self.tempdir,
Alex Kleinf2674462019-05-16 16:47:24 -0600223 empty_sysroot=True, blacklist=blacklist)
Alex Kleina2e42c42019-04-17 16:13:19 -0600224 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_COMPLETED_UNSUCCESSFULLY, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600230 self.assertFalse(output_msg.failed_packages)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600231
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700232 def testBuildTargetUnitTest(self):
233 """Test BuildTargetUnitTest successful call."""
234 input_msg = self._GetInput(board='board', result_path=self.tempdir)
235
236 result = test_service.BuildTargetUnitTestResult(0, None)
237 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
238
239 tarball_result = os.path.join(input_msg.result_path, 'unit_tests.tar')
240 self.PatchObject(test_service, 'BuildTargetUnitTestTarball',
241 return_value=tarball_result)
242
243 response = self._GetOutput()
244 test_controller.BuildTargetUnitTest(input_msg, response,
245 self.api_config)
246 self.assertEqual(response.tarball_path,
247 os.path.join(input_msg.result_path, 'unit_tests.tar'))
248
Evan Hernandez4e388a52019-05-01 12:16:33 -0600249
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700250class ChromiteUnitTestTest(cros_test_lib.MockTestCase,
251 api_config.ApiConfigMixin):
252 """Tests for the ChromiteInfoTest function."""
253
254 def setUp(self):
255 self.board = 'board'
256 self.chroot_path = '/path/to/chroot'
257
258 def _GetInput(self, chroot_path=None):
259 """Helper to build an input message instance."""
260 proto = test_pb2.ChromiteUnitTestRequest(
261 chroot={'path': chroot_path},
262 )
263 return proto
264
265 def _GetOutput(self):
266 """Helper to get an empty output message instance."""
267 return test_pb2.ChromiteUnitTestResponse()
268
269 def testValidateOnly(self):
270 """Sanity check that a validate only call does not execute any logic."""
271 patch = self.PatchObject(cros_build_lib, 'run')
272
273 input_msg = self._GetInput(chroot_path=self.chroot_path)
274 test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
275 self.validate_only_config)
276 patch.assert_not_called()
277
Michael Mortensen7a860eb2019-12-03 20:25:15 -0700278 def testMockError(self):
279 """Test mock error call does not execute any logic, returns error."""
280 patch = self.PatchObject(cros_build_lib, 'run')
281
282 input_msg = self._GetInput(chroot_path=self.chroot_path)
283 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
284 self.mock_error_config)
285 patch.assert_not_called()
286 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
287
288 def testMockCall(self):
289 """Test mock call does not execute any logic, returns success."""
290 patch = self.PatchObject(cros_build_lib, 'run')
291
292 input_msg = self._GetInput(chroot_path=self.chroot_path)
293 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
294 self.mock_call_config)
295 patch.assert_not_called()
296 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
297
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700298 def testChromiteUnitTest(self):
299 """Call ChromiteUnitTest with mocked cros_build_lib.run."""
300 request = self._GetInput(chroot_path=self.chroot_path)
301 patch = self.PatchObject(
302 cros_build_lib, 'run',
303 return_value=cros_build_lib.CommandResult(returncode=0))
304
305 test_controller.ChromiteUnitTest(request, self._GetOutput(),
306 self.api_config)
307 patch.assert_called_once()
308
309
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600310class CrosSigningTestTest(cros_test_lib.RunCommandTestCase,
311 api_config.ApiConfigMixin):
312 """CrosSigningTest tests."""
313
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700314 def setUp(self):
315 self.chroot_path = '/path/to/chroot'
316
317 def _GetInput(self, chroot_path=None):
318 """Helper to build an input message instance."""
319 proto = test_pb2.CrosSigningTestRequest(
320 chroot={'path': chroot_path},
321 )
322 return proto
323
324 def _GetOutput(self):
325 """Helper to get an empty output message instance."""
326 return test_pb2.CrosSigningTestResponse()
327
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600328 def testValidateOnly(self):
329 """Sanity check that a validate only call does not execute any logic."""
330 test_controller.CrosSigningTest(None, None, self.validate_only_config)
331 self.assertFalse(self.rc.call_count)
332
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700333 def testMockCall(self):
334 """Test mock call does not execute any logic, returns success."""
335 rc = test_controller.CrosSigningTest(None, None, self.mock_call_config)
336 self.assertFalse(self.rc.call_count)
337 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
338
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700339 def testCrosSigningTest(self):
340 """Call CrosSigningTest with mocked cros_build_lib.run."""
341 request = self._GetInput(chroot_path=self.chroot_path)
342 patch = self.PatchObject(
343 cros_build_lib, 'run',
344 return_value=cros_build_lib.CommandResult(returncode=0))
345
346 test_controller.CrosSigningTest(request, self._GetOutput(),
347 self.api_config)
348 patch.assert_called_once()
349
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600350
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600351class SimpleChromeWorkflowTestTest(cros_test_lib.MockTestCase,
352 api_config.ApiConfigMixin):
353 """Test the SimpleChromeWorkflowTest endpoint."""
354
355 @staticmethod
356 def _Output():
357 return test_pb2.SimpleChromeWorkflowTestResponse()
358
359 def _Input(self, sysroot_path=None, build_target=None, chrome_root=None,
360 goma_config=None):
361 proto = test_pb2.SimpleChromeWorkflowTestRequest()
362 if sysroot_path:
363 proto.sysroot.path = sysroot_path
364 if build_target:
365 proto.sysroot.build_target.name = build_target
366 if chrome_root:
367 proto.chrome_root = chrome_root
368 if goma_config:
369 proto.goma_config = goma_config
370 return proto
371
372 def setUp(self):
373 self.chrome_path = 'path/to/chrome'
374 self.sysroot_dir = 'build/board'
375 self.build_target = 'amd64'
376 self.mock_simple_chrome_workflow_test = self.PatchObject(
377 test_service, 'SimpleChromeWorkflowTest')
378
379 def testMissingBuildTarget(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700380 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600381 input_proto = self._Input(build_target=None, sysroot_path='/sysroot/dir',
382 chrome_root='/chrome/path')
383 with self.assertRaises(cros_build_lib.DieSystemExit):
384 test_controller.SimpleChromeWorkflowTest(input_proto, None,
385 self.api_config)
386
387 def testMissingSysrootPath(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700388 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600389 input_proto = self._Input(build_target='board', sysroot_path=None,
390 chrome_root='/chrome/path')
391 with self.assertRaises(cros_build_lib.DieSystemExit):
392 test_controller.SimpleChromeWorkflowTest(input_proto, None,
393 self.api_config)
394
395 def testMissingChromeRoot(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700396 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600397 input_proto = self._Input(build_target='board', sysroot_path='/sysroot/dir',
398 chrome_root=None)
399 with self.assertRaises(cros_build_lib.DieSystemExit):
400 test_controller.SimpleChromeWorkflowTest(input_proto, None,
401 self.api_config)
402
403 def testSimpleChromeWorkflowTest(self):
404 """Call SimpleChromeWorkflowTest with valid args and temp dir."""
405 request = self._Input(sysroot_path='sysroot_path', build_target='board',
406 chrome_root='/path/to/chrome')
407 response = self._Output()
408
409 test_controller.SimpleChromeWorkflowTest(request, response, self.api_config)
410 self.mock_simple_chrome_workflow_test.assert_called()
411
412 def testValidateOnly(self):
413 request = self._Input(sysroot_path='sysroot_path', build_target='board',
414 chrome_root='/path/to/chrome')
415 test_controller.SimpleChromeWorkflowTest(request, self._Output(),
416 self.validate_only_config)
417 self.mock_simple_chrome_workflow_test.assert_not_called()
418
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700419 def testMockCall(self):
420 """Test mock call does not execute any logic, returns success."""
421 patch = self.mock_simple_chrome_workflow_test = self.PatchObject(
422 test_service, 'SimpleChromeWorkflowTest')
423
424 request = self._Input(sysroot_path='sysroot_path', build_target='board',
425 chrome_root='/path/to/chrome')
426 rc = test_controller.SimpleChromeWorkflowTest(request, self._Output(),
427 self.mock_call_config)
428 patch.assert_not_called()
429 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
430
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600431
Alex Klein231d2da2019-07-22 16:44:45 -0600432class VmTestTest(cros_test_lib.RunCommandTestCase, api_config.ApiConfigMixin):
Evan Hernandez4e388a52019-05-01 12:16:33 -0600433 """Test the VmTest endpoint."""
434
435 def _GetInput(self, **kwargs):
436 values = dict(
437 build_target=common_pb2.BuildTarget(name='target'),
Alex Klein311b8022019-06-05 16:00:07 -0600438 vm_path=common_pb2.Path(path='/path/to/image.bin',
439 location=common_pb2.Path.INSIDE),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600440 test_harness=test_pb2.VmTestRequest.TAST,
441 vm_tests=[test_pb2.VmTestRequest.VmTest(pattern='suite')],
442 ssh_options=test_pb2.VmTestRequest.SshOptions(
Alex Klein231d2da2019-07-22 16:44:45 -0600443 port=1234, private_key_path={'path': '/path/to/id_rsa',
Alex Kleinaa705412019-06-04 15:00:30 -0600444 'location': common_pb2.Path.INSIDE}),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600445 )
446 values.update(kwargs)
447 return test_pb2.VmTestRequest(**values)
448
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700449 def _Output(self):
450 return test_pb2.VmTestResponse()
451
Alex Klein231d2da2019-07-22 16:44:45 -0600452 def testValidateOnly(self):
453 """Sanity check that a validate only call does not execute any logic."""
454 test_controller.VmTest(self._GetInput(), None, self.validate_only_config)
455 self.assertEqual(0, self.rc.call_count)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600456
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700457 def testMockCall(self):
458 """Test mock call does not execute any logic."""
459 patch = self.PatchObject(cros_build_lib, 'run')
460
461 request = self._GetInput()
462 response = self._Output()
463 # VmTest does not return a value, checking mocked value is flagged by lint.
464 test_controller.VmTest(request, response, self.mock_call_config)
465 patch.assert_not_called()
466
Evan Hernandez4e388a52019-05-01 12:16:33 -0600467 def testTastAllOptions(self):
468 """Test VmTest for Tast with all options set."""
Alex Klein231d2da2019-07-22 16:44:45 -0600469 test_controller.VmTest(self._GetInput(), None, self.api_config)
470 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700471 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600472 '--board', 'target',
473 '--image-path', '/path/to/image.bin',
474 '--tast', 'suite',
475 '--ssh-port', '1234',
476 '--private-key', '/path/to/id_rsa',
477 ])
478
479 def testAutotestAllOptions(self):
480 """Test VmTest for Autotest with all options set."""
481 input_proto = self._GetInput(test_harness=test_pb2.VmTestRequest.AUTOTEST)
Alex Klein231d2da2019-07-22 16:44:45 -0600482 test_controller.VmTest(input_proto, None, self.api_config)
483 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700484 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600485 '--board', 'target',
486 '--image-path', '/path/to/image.bin',
487 '--autotest', 'suite',
488 '--ssh-port', '1234',
489 '--private-key', '/path/to/id_rsa',
490 '--test_that-args=--whitelist-chrome-crashes',
491 ])
492
493 def testMissingBuildTarget(self):
494 """Test VmTest dies when build_target not set."""
495 input_proto = self._GetInput(build_target=None)
496 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600497 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600498
499 def testMissingVmImage(self):
500 """Test VmTest dies when vm_image not set."""
Alex Klein311b8022019-06-05 16:00:07 -0600501 input_proto = self._GetInput(vm_path=None)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600502 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600503 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600504
505 def testMissingTestHarness(self):
506 """Test VmTest dies when test_harness not specified."""
507 input_proto = self._GetInput(
508 test_harness=test_pb2.VmTestRequest.UNSPECIFIED)
509 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600510 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600511
512 def testMissingVmTests(self):
513 """Test VmTest dies when vm_tests not set."""
514 input_proto = self._GetInput(vm_tests=[])
515 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600516 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600517
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700518 def testVmTest(self):
519 """Call VmTest with valid args and temp dir."""
520 request = self._GetInput()
521 response = self._Output()
522 patch = self.PatchObject(
523 cros_build_lib, 'run',
524 return_value=cros_build_lib.CommandResult(returncode=0))
525
526 test_controller.VmTest(request, response, self.api_config)
527 patch.assert_called()
528
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600529
Alex Klein231d2da2019-07-22 16:44:45 -0600530class MoblabVmTestTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600531 """Test the MoblabVmTest endpoint."""
532
533 @staticmethod
534 def _Payload(path):
535 return test_pb2.MoblabVmTestRequest.Payload(
536 path=common_pb2.Path(path=path))
537
538 @staticmethod
539 def _Output():
540 return test_pb2.MoblabVmTestResponse()
541
542 def _Input(self):
543 return test_pb2.MoblabVmTestRequest(
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600544 chroot=common_pb2.Chroot(path=self.chroot_dir),
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600545 image_payload=self._Payload(self.image_payload_dir),
546 cache_payloads=[self._Payload(self.autotest_payload_dir)])
547
548 def setUp(self):
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600549 self.chroot_dir = '/chroot'
550 self.chroot_tmp_dir = '/chroot/tmp'
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600551 self.image_payload_dir = '/payloads/image'
552 self.autotest_payload_dir = '/payloads/autotest'
553 self.builder = 'moblab-generic-vm/R12-3.4.5-67.890'
554 self.image_cache_dir = '/mnt/moblab/cache'
555 self.image_mount_dir = '/mnt/image'
556
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600557 self.PatchObject(chroot_lib.Chroot, 'tempdir', osutils.TempDir)
Evan Hernandez655e8042019-06-13 12:50:44 -0600558
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600559 self.mock_create_moblab_vms = self.PatchObject(
560 test_service, 'CreateMoblabVm')
561 self.mock_prepare_moblab_vm_image_cache = self.PatchObject(
562 test_service, 'PrepareMoblabVmImageCache',
563 return_value=self.image_cache_dir)
564 self.mock_run_moblab_vm_tests = self.PatchObject(
565 test_service, 'RunMoblabVmTest')
566 self.mock_validate_moblab_vm_tests = self.PatchObject(
567 test_service, 'ValidateMoblabVmTest')
568
569 @contextlib.contextmanager
Alex Klein38c7d9e2019-05-08 09:31:19 -0600570 def MockLoopbackPartitions(*_args, **_kwargs):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600571 mount = mock.MagicMock()
Evan Hernandez40ee7452019-06-13 12:51:43 -0600572 mount.Mount.return_value = [self.image_mount_dir]
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600573 yield mount
Alex Klein231d2da2019-07-22 16:44:45 -0600574
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600575 self.PatchObject(image_lib, 'LoopbackPartitions', MockLoopbackPartitions)
576
Alex Klein231d2da2019-07-22 16:44:45 -0600577 def testValidateOnly(self):
578 """Sanity check that a validate only call does not execute any logic."""
579 test_controller.MoblabVmTest(self._Input(), self._Output(),
580 self.validate_only_config)
581 self.mock_create_moblab_vms.assert_not_called()
582
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700583 def testMockCall(self):
584 """Test mock call does not execute any logic."""
585 patch = self.PatchObject(key_value_store, 'LoadFile')
586
587 # MoblabVmTest does not return a value, checking mocked value is flagged by
588 # lint.
589 test_controller.MoblabVmTest(self._Input(), self._Output(),
590 self.mock_call_config)
591 patch.assert_not_called()
592
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600593 def testImageContainsBuilder(self):
594 """MoblabVmTest calls service with correct args."""
595 request = self._Input()
596 response = self._Output()
597
598 self.PatchObject(
Mike Frysingere652ba12019-09-08 00:57:43 -0400599 key_value_store, 'LoadFile',
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600600 return_value={cros_set_lsb_release.LSB_KEY_BUILDER_PATH: self.builder})
601
Alex Klein231d2da2019-07-22 16:44:45 -0600602 test_controller.MoblabVmTest(request, response, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600603
604 self.assertEqual(
605 self.mock_create_moblab_vms.call_args_list,
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600606 [mock.call(mock.ANY, self.chroot_dir, self.image_payload_dir)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600607 self.assertEqual(
608 self.mock_prepare_moblab_vm_image_cache.call_args_list,
609 [mock.call(mock.ANY, self.builder, [self.autotest_payload_dir])])
610 self.assertEqual(
611 self.mock_run_moblab_vm_tests.call_args_list,
Evan Hernandez655e8042019-06-13 12:50:44 -0600612 [mock.call(mock.ANY, mock.ANY, self.builder, self.image_cache_dir,
613 mock.ANY)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600614 self.assertEqual(
615 self.mock_validate_moblab_vm_tests.call_args_list,
616 [mock.call(mock.ANY)])
617
618 def testImageMissingBuilder(self):
619 """MoblabVmTest dies when builder path not found in lsb-release."""
620 request = self._Input()
621 response = self._Output()
622
Mike Frysingere652ba12019-09-08 00:57:43 -0400623 self.PatchObject(key_value_store, 'LoadFile', return_value={})
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600624
625 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600626 test_controller.MoblabVmTest(request, response, self.api_config)