blob: f3525b9d894957b37283b6b545fa3815fb620f45 [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
Alex Klein18a60af2020-06-11 12:08:47 -060026from chromite.lib.parser import package_info
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
Navil Perezc0b29a82020-07-07 14:17:48 +0000106 def _GetInput(self,
107 board=None,
108 result_path=None,
109 chroot_path=None,
110 cache_dir=None,
111 empty_sysroot=None,
112 packages=None,
113 blacklist=None):
Alex Kleina2e42c42019-04-17 16:13:19 -0600114 """Helper to build an input message instance."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000115 formatted_packages = []
116 for pkg in packages or []:
117 formatted_packages.append({
118 'category': pkg.category,
119 'package_name': pkg.package
120 })
Alex Kleinf2674462019-05-16 16:47:24 -0600121 formatted_blacklist = []
122 for pkg in blacklist or []:
123 formatted_blacklist.append({'category': pkg.category,
124 'package_name': pkg.package})
125
Alex Kleina2e42c42019-04-17 16:13:19 -0600126 return test_pb2.BuildTargetUnitTestRequest(
127 build_target={'name': board}, result_path=result_path,
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600128 chroot={'path': chroot_path, 'cache_dir': cache_dir},
Alex Kleinf2674462019-05-16 16:47:24 -0600129 flags={'empty_sysroot': empty_sysroot},
130 package_blacklist=formatted_blacklist,
Alex Kleina2e42c42019-04-17 16:13:19 -0600131 )
132
133 def _GetOutput(self):
134 """Helper to get an empty output message instance."""
135 return test_pb2.BuildTargetUnitTestResponse()
136
Alex Klein231d2da2019-07-22 16:44:45 -0600137 def testValidateOnly(self):
138 """Sanity check that a validate only call does not execute any logic."""
139 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
140
141 input_msg = self._GetInput(board='board', result_path=self.tempdir)
142 test_controller.BuildTargetUnitTest(input_msg, self._GetOutput(),
143 self.validate_only_config)
144 patch.assert_not_called()
145
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700146 def testMockCall(self):
147 """Test that a mock call does not execute logic, returns mocked value."""
148 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
149
150 input_msg = self._GetInput(board='board', result_path=self.tempdir)
151 response = self._GetOutput()
152 test_controller.BuildTargetUnitTest(input_msg, response,
153 self.mock_call_config)
154 patch.assert_not_called()
155 self.assertEqual(response.tarball_path,
156 os.path.join(input_msg.result_path, 'unit_tests.tar'))
157
158 def testMockError(self):
Michael Mortensen85d38402019-12-12 09:50:29 -0700159 """Test that a mock error does not execute logic, returns error."""
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700160 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
161
162 input_msg = self._GetInput(board='board', result_path=self.tempdir)
163 response = self._GetOutput()
164 rc = test_controller.BuildTargetUnitTest(input_msg, response,
165 self.mock_error_config)
166 patch.assert_not_called()
167 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
168 self.assertTrue(response.failed_packages)
169 self.assertEqual(response.failed_packages[0].category, 'foo')
170 self.assertEqual(response.failed_packages[0].package_name, 'bar')
171 self.assertEqual(response.failed_packages[1].category, 'cat')
172 self.assertEqual(response.failed_packages[1].package_name, 'pkg')
173
Alex Kleina2e42c42019-04-17 16:13:19 -0600174 def testNoArgumentFails(self):
175 """Test no arguments fails."""
176 input_msg = self._GetInput()
177 output_msg = self._GetOutput()
178 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600179 test_controller.BuildTargetUnitTest(input_msg, output_msg,
180 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600181
182 def testNoBuildTargetFails(self):
183 """Test missing build target name fails."""
184 input_msg = self._GetInput(result_path=self.tempdir)
185 output_msg = self._GetOutput()
186 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600187 test_controller.BuildTargetUnitTest(input_msg, output_msg,
188 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600189
190 def testNoResultPathFails(self):
191 """Test missing result path fails."""
192 # Missing result_path.
193 input_msg = self._GetInput(board='board')
194 output_msg = self._GetOutput()
195 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600196 test_controller.BuildTargetUnitTest(input_msg, output_msg,
197 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600198
199 def testPackageBuildFailure(self):
200 """Test handling of raised BuildPackageFailure."""
201 tempdir = osutils.TempDir(base_dir=self.tempdir)
202 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
203
204 pkgs = ['cat/pkg', 'foo/bar']
205 expected = [('cat', 'pkg'), ('foo', 'bar')]
Alex Kleina2e42c42019-04-17 16:13:19 -0600206
Alex Klein38c7d9e2019-05-08 09:31:19 -0600207 result = test_service.BuildTargetUnitTestResult(1, None)
Alex Klein18a60af2020-06-11 12:08:47 -0600208 result.failed_cpvs = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Klein38c7d9e2019-05-08 09:31:19 -0600209 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600210
211 input_msg = self._GetInput(board='board', result_path=self.tempdir)
212 output_msg = self._GetOutput()
213
Alex Klein231d2da2019-07-22 16:44:45 -0600214 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
215 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600216
Alex Klein8cb365a2019-05-15 16:24:53 -0600217 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600218 self.assertTrue(output_msg.failed_packages)
219 failed = []
220 for pi in output_msg.failed_packages:
221 failed.append((pi.category, pi.package_name))
Mike Frysinger678735c2019-09-28 18:23:28 -0400222 self.assertCountEqual(expected, failed)
Alex Kleina2e42c42019-04-17 16:13:19 -0600223
224 def testOtherBuildScriptFailure(self):
225 """Test build script failure due to non-package emerge error."""
226 tempdir = osutils.TempDir(base_dir=self.tempdir)
227 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
228
Alex Klein38c7d9e2019-05-08 09:31:19 -0600229 result = test_service.BuildTargetUnitTestResult(1, None)
230 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600231
Alex Kleinf2674462019-05-16 16:47:24 -0600232 pkgs = ['foo/bar', 'cat/pkg']
Alex Klein18a60af2020-06-11 12:08:47 -0600233 blacklist = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600234 input_msg = self._GetInput(board='board', result_path=self.tempdir,
Alex Kleinf2674462019-05-16 16:47:24 -0600235 empty_sysroot=True, blacklist=blacklist)
Alex Kleina2e42c42019-04-17 16:13:19 -0600236 output_msg = self._GetOutput()
237
Alex Klein231d2da2019-07-22 16:44:45 -0600238 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
239 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600240
Alex Klein8cb365a2019-05-15 16:24:53 -0600241 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600242 self.assertFalse(output_msg.failed_packages)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600243
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700244 def testBuildTargetUnitTest(self):
245 """Test BuildTargetUnitTest successful call."""
Navil Perezc0b29a82020-07-07 14:17:48 +0000246 pkgs = ['foo/bar', 'cat/pkg']
Alex Klein18a60af2020-06-11 12:08:47 -0600247 packages = [package_info.SplitCPV(p, strict=False) for p in pkgs]
Navil Perezc0b29a82020-07-07 14:17:48 +0000248 input_msg = self._GetInput(
249 board='board', result_path=self.tempdir, packages=packages)
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700250
251 result = test_service.BuildTargetUnitTestResult(0, None)
252 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
253
254 tarball_result = os.path.join(input_msg.result_path, 'unit_tests.tar')
255 self.PatchObject(test_service, 'BuildTargetUnitTestTarball',
256 return_value=tarball_result)
257
258 response = self._GetOutput()
259 test_controller.BuildTargetUnitTest(input_msg, response,
260 self.api_config)
261 self.assertEqual(response.tarball_path,
262 os.path.join(input_msg.result_path, 'unit_tests.tar'))
263
Evan Hernandez4e388a52019-05-01 12:16:33 -0600264
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700265class ChromiteUnitTestTest(cros_test_lib.MockTestCase,
266 api_config.ApiConfigMixin):
267 """Tests for the ChromiteInfoTest function."""
268
269 def setUp(self):
270 self.board = 'board'
271 self.chroot_path = '/path/to/chroot'
272
273 def _GetInput(self, chroot_path=None):
274 """Helper to build an input message instance."""
275 proto = test_pb2.ChromiteUnitTestRequest(
276 chroot={'path': chroot_path},
277 )
278 return proto
279
280 def _GetOutput(self):
281 """Helper to get an empty output message instance."""
282 return test_pb2.ChromiteUnitTestResponse()
283
284 def testValidateOnly(self):
285 """Sanity check that a validate only call does not execute any logic."""
286 patch = self.PatchObject(cros_build_lib, 'run')
287
288 input_msg = self._GetInput(chroot_path=self.chroot_path)
289 test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
290 self.validate_only_config)
291 patch.assert_not_called()
292
Michael Mortensen7a860eb2019-12-03 20:25:15 -0700293 def testMockError(self):
294 """Test mock error call does not execute any logic, returns error."""
295 patch = self.PatchObject(cros_build_lib, 'run')
296
297 input_msg = self._GetInput(chroot_path=self.chroot_path)
298 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
299 self.mock_error_config)
300 patch.assert_not_called()
301 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
302
303 def testMockCall(self):
304 """Test mock call does not execute any logic, returns success."""
305 patch = self.PatchObject(cros_build_lib, 'run')
306
307 input_msg = self._GetInput(chroot_path=self.chroot_path)
308 rc = test_controller.ChromiteUnitTest(input_msg, self._GetOutput(),
309 self.mock_call_config)
310 patch.assert_not_called()
311 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
312
Michael Mortensen8ca4d3b2019-11-27 09:35:22 -0700313 def testChromiteUnitTest(self):
314 """Call ChromiteUnitTest with mocked cros_build_lib.run."""
315 request = self._GetInput(chroot_path=self.chroot_path)
316 patch = self.PatchObject(
317 cros_build_lib, 'run',
318 return_value=cros_build_lib.CommandResult(returncode=0))
319
320 test_controller.ChromiteUnitTest(request, self._GetOutput(),
321 self.api_config)
322 patch.assert_called_once()
323
324
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600325class CrosSigningTestTest(cros_test_lib.RunCommandTestCase,
326 api_config.ApiConfigMixin):
327 """CrosSigningTest tests."""
328
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700329 def setUp(self):
330 self.chroot_path = '/path/to/chroot'
331
332 def _GetInput(self, chroot_path=None):
333 """Helper to build an input message instance."""
334 proto = test_pb2.CrosSigningTestRequest(
335 chroot={'path': chroot_path},
336 )
337 return proto
338
339 def _GetOutput(self):
340 """Helper to get an empty output message instance."""
341 return test_pb2.CrosSigningTestResponse()
342
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600343 def testValidateOnly(self):
344 """Sanity check that a validate only call does not execute any logic."""
345 test_controller.CrosSigningTest(None, None, self.validate_only_config)
346 self.assertFalse(self.rc.call_count)
347
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700348 def testMockCall(self):
349 """Test mock call does not execute any logic, returns success."""
350 rc = test_controller.CrosSigningTest(None, None, self.mock_call_config)
351 self.assertFalse(self.rc.call_count)
352 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
353
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700354 def testCrosSigningTest(self):
355 """Call CrosSigningTest with mocked cros_build_lib.run."""
356 request = self._GetInput(chroot_path=self.chroot_path)
357 patch = self.PatchObject(
358 cros_build_lib, 'run',
359 return_value=cros_build_lib.CommandResult(returncode=0))
360
361 test_controller.CrosSigningTest(request, self._GetOutput(),
362 self.api_config)
363 patch.assert_called_once()
364
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600365
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600366class SimpleChromeWorkflowTestTest(cros_test_lib.MockTestCase,
367 api_config.ApiConfigMixin):
368 """Test the SimpleChromeWorkflowTest endpoint."""
369
370 @staticmethod
371 def _Output():
372 return test_pb2.SimpleChromeWorkflowTestResponse()
373
374 def _Input(self, sysroot_path=None, build_target=None, chrome_root=None,
375 goma_config=None):
376 proto = test_pb2.SimpleChromeWorkflowTestRequest()
377 if sysroot_path:
378 proto.sysroot.path = sysroot_path
379 if build_target:
380 proto.sysroot.build_target.name = build_target
381 if chrome_root:
382 proto.chrome_root = chrome_root
383 if goma_config:
384 proto.goma_config = goma_config
385 return proto
386
387 def setUp(self):
388 self.chrome_path = 'path/to/chrome'
389 self.sysroot_dir = 'build/board'
390 self.build_target = 'amd64'
391 self.mock_simple_chrome_workflow_test = self.PatchObject(
392 test_service, 'SimpleChromeWorkflowTest')
393
394 def testMissingBuildTarget(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700395 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600396 input_proto = self._Input(build_target=None, sysroot_path='/sysroot/dir',
397 chrome_root='/chrome/path')
398 with self.assertRaises(cros_build_lib.DieSystemExit):
399 test_controller.SimpleChromeWorkflowTest(input_proto, None,
400 self.api_config)
401
402 def testMissingSysrootPath(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700403 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600404 input_proto = self._Input(build_target='board', sysroot_path=None,
405 chrome_root='/chrome/path')
406 with self.assertRaises(cros_build_lib.DieSystemExit):
407 test_controller.SimpleChromeWorkflowTest(input_proto, None,
408 self.api_config)
409
410 def testMissingChromeRoot(self):
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700411 """Test SimpleChromeWorkflowTest dies when build_target not set."""
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600412 input_proto = self._Input(build_target='board', sysroot_path='/sysroot/dir',
413 chrome_root=None)
414 with self.assertRaises(cros_build_lib.DieSystemExit):
415 test_controller.SimpleChromeWorkflowTest(input_proto, None,
416 self.api_config)
417
418 def testSimpleChromeWorkflowTest(self):
419 """Call SimpleChromeWorkflowTest with valid args and temp dir."""
420 request = self._Input(sysroot_path='sysroot_path', build_target='board',
421 chrome_root='/path/to/chrome')
422 response = self._Output()
423
424 test_controller.SimpleChromeWorkflowTest(request, response, self.api_config)
425 self.mock_simple_chrome_workflow_test.assert_called()
426
427 def testValidateOnly(self):
428 request = self._Input(sysroot_path='sysroot_path', build_target='board',
429 chrome_root='/path/to/chrome')
430 test_controller.SimpleChromeWorkflowTest(request, self._Output(),
431 self.validate_only_config)
432 self.mock_simple_chrome_workflow_test.assert_not_called()
433
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700434 def testMockCall(self):
435 """Test mock call does not execute any logic, returns success."""
436 patch = self.mock_simple_chrome_workflow_test = self.PatchObject(
437 test_service, 'SimpleChromeWorkflowTest')
438
439 request = self._Input(sysroot_path='sysroot_path', build_target='board',
440 chrome_root='/path/to/chrome')
441 rc = test_controller.SimpleChromeWorkflowTest(request, self._Output(),
442 self.mock_call_config)
443 patch.assert_not_called()
444 self.assertEqual(controller.RETURN_CODE_SUCCESS, rc)
445
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600446
Alex Klein231d2da2019-07-22 16:44:45 -0600447class VmTestTest(cros_test_lib.RunCommandTestCase, api_config.ApiConfigMixin):
Evan Hernandez4e388a52019-05-01 12:16:33 -0600448 """Test the VmTest endpoint."""
449
450 def _GetInput(self, **kwargs):
451 values = dict(
452 build_target=common_pb2.BuildTarget(name='target'),
Alex Klein311b8022019-06-05 16:00:07 -0600453 vm_path=common_pb2.Path(path='/path/to/image.bin',
454 location=common_pb2.Path.INSIDE),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600455 test_harness=test_pb2.VmTestRequest.TAST,
456 vm_tests=[test_pb2.VmTestRequest.VmTest(pattern='suite')],
457 ssh_options=test_pb2.VmTestRequest.SshOptions(
Alex Klein231d2da2019-07-22 16:44:45 -0600458 port=1234, private_key_path={'path': '/path/to/id_rsa',
Alex Kleinaa705412019-06-04 15:00:30 -0600459 'location': common_pb2.Path.INSIDE}),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600460 )
461 values.update(kwargs)
462 return test_pb2.VmTestRequest(**values)
463
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700464 def _Output(self):
465 return test_pb2.VmTestResponse()
466
Alex Klein231d2da2019-07-22 16:44:45 -0600467 def testValidateOnly(self):
468 """Sanity check that a validate only call does not execute any logic."""
469 test_controller.VmTest(self._GetInput(), None, self.validate_only_config)
470 self.assertEqual(0, self.rc.call_count)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600471
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700472 def testMockCall(self):
473 """Test mock call does not execute any logic."""
474 patch = self.PatchObject(cros_build_lib, 'run')
475
476 request = self._GetInput()
477 response = self._Output()
478 # VmTest does not return a value, checking mocked value is flagged by lint.
479 test_controller.VmTest(request, response, self.mock_call_config)
480 patch.assert_not_called()
481
Evan Hernandez4e388a52019-05-01 12:16:33 -0600482 def testTastAllOptions(self):
483 """Test VmTest for Tast with all options set."""
Alex Klein231d2da2019-07-22 16:44:45 -0600484 test_controller.VmTest(self._GetInput(), None, self.api_config)
485 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700486 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600487 '--board', 'target',
488 '--image-path', '/path/to/image.bin',
489 '--tast', 'suite',
490 '--ssh-port', '1234',
491 '--private-key', '/path/to/id_rsa',
492 ])
493
494 def testAutotestAllOptions(self):
495 """Test VmTest for Autotest with all options set."""
496 input_proto = self._GetInput(test_harness=test_pb2.VmTestRequest.AUTOTEST)
Alex Klein231d2da2019-07-22 16:44:45 -0600497 test_controller.VmTest(input_proto, None, self.api_config)
498 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700499 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600500 '--board', 'target',
501 '--image-path', '/path/to/image.bin',
502 '--autotest', 'suite',
503 '--ssh-port', '1234',
504 '--private-key', '/path/to/id_rsa',
Greg Edelstondcb0e912020-08-31 11:09:40 -0600505 '--test_that-args=--allow-chrome-crashes',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600506 ])
507
508 def testMissingBuildTarget(self):
509 """Test VmTest dies when build_target not set."""
510 input_proto = self._GetInput(build_target=None)
511 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600512 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600513
514 def testMissingVmImage(self):
515 """Test VmTest dies when vm_image not set."""
Alex Klein311b8022019-06-05 16:00:07 -0600516 input_proto = self._GetInput(vm_path=None)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600517 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600518 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600519
520 def testMissingTestHarness(self):
521 """Test VmTest dies when test_harness not specified."""
522 input_proto = self._GetInput(
523 test_harness=test_pb2.VmTestRequest.UNSPECIFIED)
524 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600525 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600526
527 def testMissingVmTests(self):
528 """Test VmTest dies when vm_tests not set."""
529 input_proto = self._GetInput(vm_tests=[])
530 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600531 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600532
Michael Mortensen82cd62d2019-12-01 14:58:54 -0700533 def testVmTest(self):
534 """Call VmTest with valid args and temp dir."""
535 request = self._GetInput()
536 response = self._Output()
537 patch = self.PatchObject(
538 cros_build_lib, 'run',
539 return_value=cros_build_lib.CommandResult(returncode=0))
540
541 test_controller.VmTest(request, response, self.api_config)
542 patch.assert_called()
543
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600544
Alex Klein231d2da2019-07-22 16:44:45 -0600545class MoblabVmTestTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600546 """Test the MoblabVmTest endpoint."""
547
548 @staticmethod
549 def _Payload(path):
550 return test_pb2.MoblabVmTestRequest.Payload(
551 path=common_pb2.Path(path=path))
552
553 @staticmethod
554 def _Output():
555 return test_pb2.MoblabVmTestResponse()
556
557 def _Input(self):
558 return test_pb2.MoblabVmTestRequest(
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600559 chroot=common_pb2.Chroot(path=self.chroot_dir),
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600560 image_payload=self._Payload(self.image_payload_dir),
561 cache_payloads=[self._Payload(self.autotest_payload_dir)])
562
563 def setUp(self):
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600564 self.chroot_dir = '/chroot'
565 self.chroot_tmp_dir = '/chroot/tmp'
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600566 self.image_payload_dir = '/payloads/image'
567 self.autotest_payload_dir = '/payloads/autotest'
568 self.builder = 'moblab-generic-vm/R12-3.4.5-67.890'
569 self.image_cache_dir = '/mnt/moblab/cache'
570 self.image_mount_dir = '/mnt/image'
571
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600572 self.PatchObject(chroot_lib.Chroot, 'tempdir', osutils.TempDir)
Evan Hernandez655e8042019-06-13 12:50:44 -0600573
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600574 self.mock_create_moblab_vms = self.PatchObject(
575 test_service, 'CreateMoblabVm')
576 self.mock_prepare_moblab_vm_image_cache = self.PatchObject(
577 test_service, 'PrepareMoblabVmImageCache',
578 return_value=self.image_cache_dir)
579 self.mock_run_moblab_vm_tests = self.PatchObject(
580 test_service, 'RunMoblabVmTest')
581 self.mock_validate_moblab_vm_tests = self.PatchObject(
582 test_service, 'ValidateMoblabVmTest')
583
584 @contextlib.contextmanager
Alex Klein38c7d9e2019-05-08 09:31:19 -0600585 def MockLoopbackPartitions(*_args, **_kwargs):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600586 mount = mock.MagicMock()
Evan Hernandez40ee7452019-06-13 12:51:43 -0600587 mount.Mount.return_value = [self.image_mount_dir]
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600588 yield mount
Alex Klein231d2da2019-07-22 16:44:45 -0600589
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600590 self.PatchObject(image_lib, 'LoopbackPartitions', MockLoopbackPartitions)
591
Alex Klein231d2da2019-07-22 16:44:45 -0600592 def testValidateOnly(self):
593 """Sanity check that a validate only call does not execute any logic."""
594 test_controller.MoblabVmTest(self._Input(), self._Output(),
595 self.validate_only_config)
596 self.mock_create_moblab_vms.assert_not_called()
597
Michael Mortensen7a7646d2019-12-12 15:36:14 -0700598 def testMockCall(self):
599 """Test mock call does not execute any logic."""
600 patch = self.PatchObject(key_value_store, 'LoadFile')
601
602 # MoblabVmTest does not return a value, checking mocked value is flagged by
603 # lint.
604 test_controller.MoblabVmTest(self._Input(), self._Output(),
605 self.mock_call_config)
606 patch.assert_not_called()
607
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600608 def testImageContainsBuilder(self):
609 """MoblabVmTest calls service with correct args."""
610 request = self._Input()
611 response = self._Output()
612
613 self.PatchObject(
Mike Frysingere652ba12019-09-08 00:57:43 -0400614 key_value_store, 'LoadFile',
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600615 return_value={cros_set_lsb_release.LSB_KEY_BUILDER_PATH: self.builder})
616
Alex Klein231d2da2019-07-22 16:44:45 -0600617 test_controller.MoblabVmTest(request, response, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600618
619 self.assertEqual(
620 self.mock_create_moblab_vms.call_args_list,
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600621 [mock.call(mock.ANY, self.chroot_dir, self.image_payload_dir)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600622 self.assertEqual(
623 self.mock_prepare_moblab_vm_image_cache.call_args_list,
624 [mock.call(mock.ANY, self.builder, [self.autotest_payload_dir])])
625 self.assertEqual(
626 self.mock_run_moblab_vm_tests.call_args_list,
Evan Hernandez655e8042019-06-13 12:50:44 -0600627 [mock.call(mock.ANY, mock.ANY, self.builder, self.image_cache_dir,
628 mock.ANY)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600629 self.assertEqual(
630 self.mock_validate_moblab_vm_tests.call_args_list,
631 [mock.call(mock.ANY)])
632
633 def testImageMissingBuilder(self):
634 """MoblabVmTest dies when builder path not found in lsb-release."""
635 request = self._Input()
636 response = self._Output()
637
Mike Frysingere652ba12019-09-08 00:57:43 -0400638 self.PatchObject(key_value_store, 'LoadFile', return_value={})
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600639
640 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600641 test_controller.MoblabVmTest(request, response, self.api_config)