blob: 5a9f434359006988e0f204f27477f01d5a875a9b [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
Mike Frysingeref94e4c2020-02-10 23:59:54 -050012
Alex Kleinfa6ebdc2019-05-10 10:57:31 -060013import mock
14
Alex Klein231d2da2019-07-22 16:44:45 -060015from chromite.api import api_config
Alex Klein8cb365a2019-05-15 16:24:53 -060016from chromite.api import controller
Alex Kleina2e42c42019-04-17 16:13:19 -060017from chromite.api.controller import test as test_controller
Evan Hernandez4e388a52019-05-01 12:16:33 -060018from chromite.api.gen.chromiumos import common_pb2
Alex Kleina2e42c42019-04-17 16:13:19 -060019from chromite.api.gen.chromite.api import test_pb2
Evan Hernandeze1e05d32019-07-19 12:32:18 -060020from chromite.lib import chroot_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060021from chromite.lib import cros_build_lib
22from chromite.lib import cros_test_lib
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060023from chromite.lib import image_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060024from chromite.lib import osutils
Alex Klein18a60af2020-06-11 12:08:47 -060025from chromite.lib.parser import package_info
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060026from chromite.scripts import cros_set_lsb_release
27from chromite.service import test as test_service
Mike Frysingere652ba12019-09-08 00:57:43 -040028from chromite.utils import key_value_store
Alex Kleina2e42c42019-04-17 16:13:19 -060029
30
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -070031class DebugInfoTestTest(cros_test_lib.MockTempDirTestCase,
32 api_config.ApiConfigMixin):
33 """Tests for the DebugInfoTest function."""
34
35 def setUp(self):
36 self.board = 'board'
37 self.chroot_path = os.path.join(self.tempdir, 'chroot')
38 self.sysroot_path = '/build/board'
39 self.full_sysroot_path = os.path.join(self.chroot_path,
40 self.sysroot_path.lstrip(os.sep))
41 osutils.SafeMakedirs(self.full_sysroot_path)
42
43 def _GetInput(self, sysroot_path=None, build_target=None):
44 """Helper to build an input message instance."""
45 proto = test_pb2.DebugInfoTestRequest()
46 if sysroot_path:
47 proto.sysroot.path = sysroot_path
48 if build_target:
49 proto.sysroot.build_target.name = build_target
50 return proto
51
52 def _GetOutput(self):
53 """Helper to get an empty output message instance."""
54 return test_pb2.DebugInfoTestResponse()
55
56 def testValidateOnly(self):
57 """Sanity check that a validate only call does not execute any logic."""
58 patch = self.PatchObject(test_service, 'DebugInfoTest')
59 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
60 test_controller.DebugInfoTest(input_msg, self._GetOutput(),
61 self.validate_only_config)
62 patch.assert_not_called()
63
Michael Mortensen85d38402019-12-12 09:50:29 -070064 def testMockError(self):
65 """Test mock error call does not execute any logic, returns error."""
66 patch = self.PatchObject(test_service, 'DebugInfoTest')
67
68 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
69 rc = test_controller.DebugInfoTest(input_msg, self._GetOutput(),
70 self.mock_error_config)
71 patch.assert_not_called()
72 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
73
74 def testMockCall(self):
75 """Test mock call does not execute any logic, returns success."""
76 patch = self.PatchObject(test_service, 'DebugInfoTest')
77
78 input_msg = self._GetInput(sysroot_path=self.full_sysroot_path)
79 rc = test_controller.DebugInfoTest(input_msg, self._GetOutput(),
80 self.mock_call_config)
81 patch.assert_not_called()
82 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
83
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -070084 def testNoBuildTargetNoSysrootFails(self):
85 """Test missing build target name and sysroot path fails."""
86 input_msg = self._GetInput()
87 output_msg = self._GetOutput()
88 with self.assertRaises(cros_build_lib.DieSystemExit):
89 test_controller.DebugInfoTest(input_msg, output_msg, self.api_config)
90
91 def testDebugInfoTest(self):
92 """Call DebugInfoTest with valid sysroot_path."""
93 request = self._GetInput(sysroot_path=self.full_sysroot_path)
94
95 test_controller.DebugInfoTest(request, self._GetOutput(), self.api_config)
96
97
Alex Klein231d2da2019-07-22 16:44:45 -060098class BuildTargetUnitTestTest(cros_test_lib.MockTempDirTestCase,
99 api_config.ApiConfigMixin):
Alex Kleina2e42c42019-04-17 16:13:19 -0600100 """Tests for the UnitTest function."""
101
Navil Perezc0b29a82020-07-07 14:17:48 +0000102 def _GetInput(self,
103 board=None,
104 result_path=None,
105 chroot_path=None,
106 cache_dir=None,
107 empty_sysroot=None,
108 packages=None,
Alex Kleinb64e5f82020-09-23 10:55:31 -0600109 blocklist=None):
Alex Kleina2e42c42019-04-17 16:13:19 -0600110 """Helper to build an input message instance."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000111 formatted_packages = []
112 for pkg in packages or []:
113 formatted_packages.append({
114 'category': pkg.category,
115 'package_name': pkg.package
116 })
Alex Kleinb64e5f82020-09-23 10:55:31 -0600117 formatted_blocklist = []
118 for pkg in blocklist or []:
119 formatted_blocklist.append({'category': pkg.category,
Alex Kleinf2674462019-05-16 16:47:24 -0600120 'package_name': pkg.package})
121
Alex Kleina2e42c42019-04-17 16:13:19 -0600122 return test_pb2.BuildTargetUnitTestRequest(
123 build_target={'name': board}, result_path=result_path,
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600124 chroot={'path': chroot_path, 'cache_dir': cache_dir},
Alex Kleinf2674462019-05-16 16:47:24 -0600125 flags={'empty_sysroot': empty_sysroot},
Alex Kleinb64e5f82020-09-23 10:55:31 -0600126 package_blacklist=formatted_blocklist,
Alex Kleina2e42c42019-04-17 16:13:19 -0600127 )
128
129 def _GetOutput(self):
130 """Helper to get an empty output message instance."""
131 return test_pb2.BuildTargetUnitTestResponse()
132
Alex Klein231d2da2019-07-22 16:44:45 -0600133 def testValidateOnly(self):
134 """Sanity check that a validate only call does not execute any logic."""
135 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
136
137 input_msg = self._GetInput(board='board', result_path=self.tempdir)
138 test_controller.BuildTargetUnitTest(input_msg, self._GetOutput(),
139 self.validate_only_config)
140 patch.assert_not_called()
141
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700142 def testMockCall(self):
143 """Test that a mock call does not execute logic, returns mocked value."""
144 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
145
146 input_msg = self._GetInput(board='board', result_path=self.tempdir)
147 response = self._GetOutput()
148 test_controller.BuildTargetUnitTest(input_msg, response,
149 self.mock_call_config)
150 patch.assert_not_called()
151 self.assertEqual(response.tarball_path,
152 os.path.join(input_msg.result_path, 'unit_tests.tar'))
153
154 def testMockError(self):
Michael Mortensen85d38402019-12-12 09:50:29 -0700155 """Test that a mock error does not execute logic, returns error."""
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700156 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
157
158 input_msg = self._GetInput(board='board', result_path=self.tempdir)
159 response = self._GetOutput()
160 rc = test_controller.BuildTargetUnitTest(input_msg, response,
161 self.mock_error_config)
162 patch.assert_not_called()
163 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
164 self.assertTrue(response.failed_packages)
165 self.assertEqual(response.failed_packages[0].category, 'foo')
166 self.assertEqual(response.failed_packages[0].package_name, 'bar')
167 self.assertEqual(response.failed_packages[1].category, 'cat')
168 self.assertEqual(response.failed_packages[1].package_name, 'pkg')
169
Alex Kleina2e42c42019-04-17 16:13:19 -0600170 def testNoArgumentFails(self):
171 """Test no arguments fails."""
172 input_msg = self._GetInput()
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 testNoBuildTargetFails(self):
179 """Test missing build target name fails."""
180 input_msg = self._GetInput(result_path=self.tempdir)
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 testNoResultPathFails(self):
187 """Test missing result path fails."""
188 # Missing result_path.
189 input_msg = self._GetInput(board='board')
190 output_msg = self._GetOutput()
191 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600192 test_controller.BuildTargetUnitTest(input_msg, output_msg,
193 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600194
195 def testPackageBuildFailure(self):
196 """Test handling of raised BuildPackageFailure."""
197 tempdir = osutils.TempDir(base_dir=self.tempdir)
198 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
199
200 pkgs = ['cat/pkg', 'foo/bar']
201 expected = [('cat', 'pkg'), ('foo', 'bar')]
Alex Kleina2e42c42019-04-17 16:13:19 -0600202
Alex Klein38c7d9e2019-05-08 09:31:19 -0600203 result = test_service.BuildTargetUnitTestResult(1, None)
Alex Klein18a60af2020-06-11 12:08:47 -0600204 result.failed_cpvs = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Klein38c7d9e2019-05-08 09:31:19 -0600205 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600206
207 input_msg = self._GetInput(board='board', result_path=self.tempdir)
208 output_msg = self._GetOutput()
209
Alex Klein231d2da2019-07-22 16:44:45 -0600210 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
211 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600212
Alex Klein8cb365a2019-05-15 16:24:53 -0600213 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600214 self.assertTrue(output_msg.failed_packages)
215 failed = []
216 for pi in output_msg.failed_packages:
217 failed.append((pi.category, pi.package_name))
Mike Frysinger678735c2019-09-28 18:23:28 -0400218 self.assertCountEqual(expected, failed)
Alex Kleina2e42c42019-04-17 16:13:19 -0600219
220 def testOtherBuildScriptFailure(self):
221 """Test build script failure due to non-package emerge error."""
222 tempdir = osutils.TempDir(base_dir=self.tempdir)
223 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
224
Alex Klein38c7d9e2019-05-08 09:31:19 -0600225 result = test_service.BuildTargetUnitTestResult(1, None)
226 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600227
Alex Kleinf2674462019-05-16 16:47:24 -0600228 pkgs = ['foo/bar', 'cat/pkg']
Alex Kleinb64e5f82020-09-23 10:55:31 -0600229 blocklist = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600230 input_msg = self._GetInput(board='board', result_path=self.tempdir,
Alex Kleinb64e5f82020-09-23 10:55:31 -0600231 empty_sysroot=True, blocklist=blocklist)
Alex Kleina2e42c42019-04-17 16:13:19 -0600232 output_msg = self._GetOutput()
233
Alex Klein231d2da2019-07-22 16:44:45 -0600234 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
235 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600236
Alex Klein8cb365a2019-05-15 16:24:53 -0600237 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600238 self.assertFalse(output_msg.failed_packages)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600239
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700240 def testBuildTargetUnitTest(self):
241 """Test BuildTargetUnitTest successful call."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000242 pkgs = ['foo/bar', 'cat/pkg']
Alex Klein18a60af2020-06-11 12:08:47 -0600243 packages = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Navil Perezc0b29a82020-07-07 14:17:48 +0000244 input_msg = self._GetInput(
245 board='board', result_path=self.tempdir, packages=packages)
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700246
247 result = test_service.BuildTargetUnitTestResult(0, None)
248 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
249
250 tarball_result = os.path.join(input_msg.result_path, 'unit_tests.tar')
251 self.PatchObject(test_service, 'BuildTargetUnitTestTarball',
252 return_value=tarball_result)
253
254 response = self._GetOutput()
255 test_controller.BuildTargetUnitTest(input_msg, response,
256 self.api_config)
257 self.assertEqual(response.tarball_path,
258 os.path.join(input_msg.result_path, 'unit_tests.tar'))
259
Evan Hernandez4e388a52019-05-01 12:16:33 -0600260
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700261class ChromiteUnitTestTest(cros_test_lib.MockTestCase,
262 api_config.ApiConfigMixin):
263 """Tests for the ChromiteInfoTest function."""
264
265 def setUp(self):
266 self.board = 'board'
267 self.chroot_path = '/path/to/chroot'
268
269 def _GetInput(self, chroot_path=None):
270 """Helper to build an input message instance."""
271 proto = test_pb2.ChromiteUnitTestRequest(
272 chroot={'path': chroot_path},
273 )
274 return proto
275
276 def _GetOutput(self):
277 """Helper to get an empty output message instance."""
278 return test_pb2.ChromiteUnitTestResponse()
279
280 def testValidateOnly(self):
281 """Sanity check that a validate only call does not execute any logic."""
282 patch = self.PatchObject(cros_build_lib, 'run')
283
284 input_msg = self._GetInput(chroot_path=self.chroot_path)
285 test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
286 self.validate_only_config)
287 patch.assert_not_called()
288
Michael Mortensen7a860eb2019-12-03 20:25:15 -0700289 def testMockError(self):
290 """Test mock error call does not execute any logic, returns error."""
291 patch = self.PatchObject(cros_build_lib, 'run')
292
293 input_msg = self._GetInput(chroot_path=self.chroot_path)
294 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
295 self.mock_error_config)
296 patch.assert_not_called()
297 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
298
299 def testMockCall(self):
300 """Test mock call does not execute any logic, returns success."""
301 patch = self.PatchObject(cros_build_lib, 'run')
302
303 input_msg = self._GetInput(chroot_path=self.chroot_path)
304 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
305 self.mock_call_config)
306 patch.assert_not_called()
307 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
308
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700309 def testChromiteUnitTest(self):
310 """Call ChromiteUnitTest with mocked cros_build_lib.run."""
311 request = self._GetInput(chroot_path=self.chroot_path)
312 patch = self.PatchObject(
313 cros_build_lib, 'run',
314 return_value=cros_build_lib.CommandResult(returncode=0))
315
316 test_controller.ChromiteUnitTest(request, self._GetOutput(),
317 self.api_config)
318 patch.assert_called_once()
319
320
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600321class CrosSigningTestTest(cros_test_lib.RunCommandTestCase,
322 api_config.ApiConfigMixin):
323 """CrosSigningTest tests."""
324
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700325 def setUp(self):
326 self.chroot_path = '/path/to/chroot'
327
328 def _GetInput(self, chroot_path=None):
329 """Helper to build an input message instance."""
330 proto = test_pb2.CrosSigningTestRequest(
331 chroot={'path': chroot_path},
332 )
333 return proto
334
335 def _GetOutput(self):
336 """Helper to get an empty output message instance."""
337 return test_pb2.CrosSigningTestResponse()
338
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600339 def testValidateOnly(self):
340 """Sanity check that a validate only call does not execute any logic."""
341 test_controller.CrosSigningTest(None, None, self.validate_only_config)
342 self.assertFalse(self.rc.call_count)
343
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700344 def testMockCall(self):
345 """Test mock call does not execute any logic, returns success."""
346 rc = test_controller.CrosSigningTest(None, None, self.mock_call_config)
347 self.assertFalse(self.rc.call_count)
348 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
349
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700350 def testCrosSigningTest(self):
351 """Call CrosSigningTest with mocked cros_build_lib.run."""
352 request = self._GetInput(chroot_path=self.chroot_path)
353 patch = self.PatchObject(
354 cros_build_lib, 'run',
355 return_value=cros_build_lib.CommandResult(returncode=0))
356
357 test_controller.CrosSigningTest(request, self._GetOutput(),
358 self.api_config)
359 patch.assert_called_once()
360
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600361
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600362class SimpleChromeWorkflowTestTest(cros_test_lib.MockTestCase,
363 api_config.ApiConfigMixin):
364 """Test the SimpleChromeWorkflowTest endpoint."""
365
366 @staticmethod
367 def _Output():
368 return test_pb2.SimpleChromeWorkflowTestResponse()
369
370 def _Input(self, sysroot_path=None, build_target=None, chrome_root=None,
371 goma_config=None):
372 proto = test_pb2.SimpleChromeWorkflowTestRequest()
373 if sysroot_path:
374 proto.sysroot.path = sysroot_path
375 if build_target:
376 proto.sysroot.build_target.name = build_target
377 if chrome_root:
378 proto.chrome_root = chrome_root
379 if goma_config:
380 proto.goma_config = goma_config
381 return proto
382
383 def setUp(self):
384 self.chrome_path = 'path/to/chrome'
385 self.sysroot_dir = 'build/board'
386 self.build_target = 'amd64'
387 self.mock_simple_chrome_workflow_test = self.PatchObject(
388 test_service, 'SimpleChromeWorkflowTest')
389
390 def testMissingBuildTarget(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700391 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600392 input_proto = self._Input(build_target=None, sysroot_path='/sysroot/dir',
393 chrome_root='/chrome/path')
394 with self.assertRaises(cros_build_lib.DieSystemExit):
395 test_controller.SimpleChromeWorkflowTest(input_proto, None,
396 self.api_config)
397
398 def testMissingSysrootPath(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700399 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600400 input_proto = self._Input(build_target='board', sysroot_path=None,
401 chrome_root='/chrome/path')
402 with self.assertRaises(cros_build_lib.DieSystemExit):
403 test_controller.SimpleChromeWorkflowTest(input_proto, None,
404 self.api_config)
405
406 def testMissingChromeRoot(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700407 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600408 input_proto = self._Input(build_target='board', sysroot_path='/sysroot/dir',
409 chrome_root=None)
410 with self.assertRaises(cros_build_lib.DieSystemExit):
411 test_controller.SimpleChromeWorkflowTest(input_proto, None,
412 self.api_config)
413
414 def testSimpleChromeWorkflowTest(self):
415 """Call SimpleChromeWorkflowTest with valid args and temp dir."""
416 request = self._Input(sysroot_path='sysroot_path', build_target='board',
417 chrome_root='/path/to/chrome')
418 response = self._Output()
419
420 test_controller.SimpleChromeWorkflowTest(request, response, self.api_config)
421 self.mock_simple_chrome_workflow_test.assert_called()
422
423 def testValidateOnly(self):
424 request = self._Input(sysroot_path='sysroot_path', build_target='board',
425 chrome_root='/path/to/chrome')
426 test_controller.SimpleChromeWorkflowTest(request, self._Output(),
427 self.validate_only_config)
428 self.mock_simple_chrome_workflow_test.assert_not_called()
429
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700430 def testMockCall(self):
431 """Test mock call does not execute any logic, returns success."""
432 patch = self.mock_simple_chrome_workflow_test = self.PatchObject(
433 test_service, 'SimpleChromeWorkflowTest')
434
435 request = self._Input(sysroot_path='sysroot_path', build_target='board',
436 chrome_root='/path/to/chrome')
437 rc = test_controller.SimpleChromeWorkflowTest(request, self._Output(),
438 self.mock_call_config)
439 patch.assert_not_called()
440 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
441
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600442
Alex Klein231d2da2019-07-22 16:44:45 -0600443class VmTestTest(cros_test_lib.RunCommandTestCase, api_config.ApiConfigMixin):
Evan Hernandez4e388a52019-05-01 12:16:33 -0600444 """Test the VmTest endpoint."""
445
446 def _GetInput(self, **kwargs):
447 values = dict(
448 build_target=common_pb2.BuildTarget(name='target'),
Alex Klein311b8022019-06-05 16:00:07 -0600449 vm_path=common_pb2.Path(path='/path/to/image.bin',
450 location=common_pb2.Path.INSIDE),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600451 test_harness=test_pb2.VmTestRequest.TAST,
452 vm_tests=[test_pb2.VmTestRequest.VmTest(pattern='suite')],
453 ssh_options=test_pb2.VmTestRequest.SshOptions(
Alex Klein231d2da2019-07-22 16:44:45 -0600454 port=1234, private_key_path={'path': '/path/to/id_rsa',
Alex Kleinaa705412019-06-04 15:00:30 -0600455 'location': common_pb2.Path.INSIDE}),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600456 )
457 values.update(kwargs)
458 return test_pb2.VmTestRequest(**values)
459
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700460 def _Output(self):
461 return test_pb2.VmTestResponse()
462
Alex Klein231d2da2019-07-22 16:44:45 -0600463 def testValidateOnly(self):
464 """Sanity check that a validate only call does not execute any logic."""
465 test_controller.VmTest(self._GetInput(), None, self.validate_only_config)
466 self.assertEqual(0, self.rc.call_count)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600467
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700468 def testMockCall(self):
469 """Test mock call does not execute any logic."""
470 patch = self.PatchObject(cros_build_lib, 'run')
471
472 request = self._GetInput()
473 response = self._Output()
474 # VmTest does not return a value, checking mocked value is flagged by lint.
475 test_controller.VmTest(request, response, self.mock_call_config)
476 patch.assert_not_called()
477
Evan Hernandez4e388a52019-05-01 12:16:33 -0600478 def testTastAllOptions(self):
479 """Test VmTest for Tast with all options set."""
Alex Klein231d2da2019-07-22 16:44:45 -0600480 test_controller.VmTest(self._GetInput(), None, self.api_config)
481 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700482 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600483 '--board', 'target',
484 '--image-path', '/path/to/image.bin',
485 '--tast', 'suite',
486 '--ssh-port', '1234',
487 '--private-key', '/path/to/id_rsa',
488 ])
489
490 def testAutotestAllOptions(self):
491 """Test VmTest for Autotest with all options set."""
492 input_proto = self._GetInput(test_harness=test_pb2.VmTestRequest.AUTOTEST)
Alex Klein231d2da2019-07-22 16:44:45 -0600493 test_controller.VmTest(input_proto, None, self.api_config)
494 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700495 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600496 '--board', 'target',
497 '--image-path', '/path/to/image.bin',
498 '--autotest', 'suite',
499 '--ssh-port', '1234',
500 '--private-key', '/path/to/id_rsa',
Greg Edelstondcb0e912020-08-31 11:09:40 -0600501 '--test_that-args=--allow-chrome-crashes',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600502 ])
503
504 def testMissingBuildTarget(self):
505 """Test VmTest dies when build_target not set."""
506 input_proto = self._GetInput(build_target=None)
507 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600508 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600509
510 def testMissingVmImage(self):
511 """Test VmTest dies when vm_image not set."""
Alex Klein311b8022019-06-05 16:00:07 -0600512 input_proto = self._GetInput(vm_path=None)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600513 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600514 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600515
516 def testMissingTestHarness(self):
517 """Test VmTest dies when test_harness not specified."""
518 input_proto = self._GetInput(
519 test_harness=test_pb2.VmTestRequest.UNSPECIFIED)
520 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600521 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600522
523 def testMissingVmTests(self):
524 """Test VmTest dies when vm_tests not set."""
525 input_proto = self._GetInput(vm_tests=[])
526 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600527 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600528
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700529 def testVmTest(self):
530 """Call VmTest with valid args and temp dir."""
531 request = self._GetInput()
532 response = self._Output()
533 patch = self.PatchObject(
534 cros_build_lib, 'run',
535 return_value=cros_build_lib.CommandResult(returncode=0))
536
537 test_controller.VmTest(request, response, self.api_config)
538 patch.assert_called()
539
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600540
Alex Klein231d2da2019-07-22 16:44:45 -0600541class MoblabVmTestTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600542 """Test the MoblabVmTest endpoint."""
543
544 @staticmethod
545 def _Payload(path):
546 return test_pb2.MoblabVmTestRequest.Payload(
547 path=common_pb2.Path(path=path))
548
549 @staticmethod
550 def _Output():
551 return test_pb2.MoblabVmTestResponse()
552
553 def _Input(self):
554 return test_pb2.MoblabVmTestRequest(
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600555 chroot=common_pb2.Chroot(path=self.chroot_dir),
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600556 image_payload=self._Payload(self.image_payload_dir),
557 cache_payloads=[self._Payload(self.autotest_payload_dir)])
558
559 def setUp(self):
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600560 self.chroot_dir = '/chroot'
561 self.chroot_tmp_dir = '/chroot/tmp'
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600562 self.image_payload_dir = '/payloads/image'
563 self.autotest_payload_dir = '/payloads/autotest'
564 self.builder = 'moblab-generic-vm/R12-3.4.5-67.890'
565 self.image_cache_dir = '/mnt/moblab/cache'
566 self.image_mount_dir = '/mnt/image'
567
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600568 self.PatchObject(chroot_lib.Chroot, 'tempdir', osutils.TempDir)
Evan Hernandez655e8042019-06-13 12:50:44 -0600569
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600570 self.mock_create_moblab_vms = self.PatchObject(
571 test_service, 'CreateMoblabVm')
572 self.mock_prepare_moblab_vm_image_cache = self.PatchObject(
573 test_service, 'PrepareMoblabVmImageCache',
574 return_value=self.image_cache_dir)
575 self.mock_run_moblab_vm_tests = self.PatchObject(
576 test_service, 'RunMoblabVmTest')
577 self.mock_validate_moblab_vm_tests = self.PatchObject(
578 test_service, 'ValidateMoblabVmTest')
579
580 @contextlib.contextmanager
Alex Klein38c7d9e2019-05-08 09:31:19 -0600581 def MockLoopbackPartitions(*_args, **_kwargs):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600582 mount = mock.MagicMock()
Evan Hernandez40ee7452019-06-13 12:51:43 -0600583 mount.Mount.return_value = [self.image_mount_dir]
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600584 yield mount
Alex Klein231d2da2019-07-22 16:44:45 -0600585
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600586 self.PatchObject(image_lib, 'LoopbackPartitions', MockLoopbackPartitions)
587
Alex Klein231d2da2019-07-22 16:44:45 -0600588 def testValidateOnly(self):
589 """Sanity check that a validate only call does not execute any logic."""
590 test_controller.MoblabVmTest(self._Input(), self._Output(),
591 self.validate_only_config)
592 self.mock_create_moblab_vms.assert_not_called()
593
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700594 def testMockCall(self):
595 """Test mock call does not execute any logic."""
596 patch = self.PatchObject(key_value_store, 'LoadFile')
597
598 # MoblabVmTest does not return a value, checking mocked value is flagged by
599 # lint.
600 test_controller.MoblabVmTest(self._Input(), self._Output(),
601 self.mock_call_config)
602 patch.assert_not_called()
603
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600604 def testImageContainsBuilder(self):
605 """MoblabVmTest calls service with correct args."""
606 request = self._Input()
607 response = self._Output()
608
609 self.PatchObject(
Mike Frysingere652ba12019-09-08 00:57:43 -0400610 key_value_store, 'LoadFile',
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600611 return_value={cros_set_lsb_release.LSB_KEY_BUILDER_PATH: self.builder})
612
Alex Klein231d2da2019-07-22 16:44:45 -0600613 test_controller.MoblabVmTest(request, response, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600614
615 self.assertEqual(
616 self.mock_create_moblab_vms.call_args_list,
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600617 [mock.call(mock.ANY, self.chroot_dir, self.image_payload_dir)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600618 self.assertEqual(
619 self.mock_prepare_moblab_vm_image_cache.call_args_list,
620 [mock.call(mock.ANY, self.builder, [self.autotest_payload_dir])])
621 self.assertEqual(
622 self.mock_run_moblab_vm_tests.call_args_list,
Evan Hernandez655e8042019-06-13 12:50:44 -0600623 [mock.call(mock.ANY, mock.ANY, self.builder, self.image_cache_dir,
624 mock.ANY)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600625 self.assertEqual(
626 self.mock_validate_moblab_vm_tests.call_args_list,
627 [mock.call(mock.ANY)])
628
629 def testImageMissingBuilder(self):
630 """MoblabVmTest dies when builder path not found in lsb-release."""
631 request = self._Input()
632 response = self._Output()
633
Mike Frysingere652ba12019-09-08 00:57:43 -0400634 self.PatchObject(key_value_store, 'LoadFile', return_value={})
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600635
636 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600637 test_controller.MoblabVmTest(request, response, self.api_config)