blob: 86f1b504156c57541dd8b5fb9737e279b35cbab9 [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
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060010import contextlib
Alex Kleinfa6ebdc2019-05-10 10:57:31 -060011import mock
12
Alex Klein231d2da2019-07-22 16:44:45 -060013from chromite.api import api_config
Alex Klein8cb365a2019-05-15 16:24:53 -060014from chromite.api import controller
Alex Kleina2e42c42019-04-17 16:13:19 -060015from chromite.api.controller import test as test_controller
Evan Hernandez4e388a52019-05-01 12:16:33 -060016from chromite.api.gen.chromiumos import common_pb2
Alex Kleina2e42c42019-04-17 16:13:19 -060017from chromite.api.gen.chromite.api import test_pb2
Evan Hernandeze1e05d32019-07-19 12:32:18 -060018from chromite.lib import chroot_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060019from chromite.lib import cros_build_lib
20from chromite.lib import cros_test_lib
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060021from chromite.lib import image_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060022from chromite.lib import osutils
23from chromite.lib import portage_util
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060024from chromite.scripts import cros_set_lsb_release
25from chromite.service import test as test_service
Mike Frysingere652ba12019-09-08 00:57:43 -040026from chromite.utils import key_value_store
Alex Kleina2e42c42019-04-17 16:13:19 -060027
28
Alex Klein231d2da2019-07-22 16:44:45 -060029class BuildTargetUnitTestTest(cros_test_lib.MockTempDirTestCase,
30 api_config.ApiConfigMixin):
Alex Kleina2e42c42019-04-17 16:13:19 -060031 """Tests for the UnitTest function."""
32
33 def _GetInput(self, board=None, result_path=None, chroot_path=None,
Alex Kleinf2674462019-05-16 16:47:24 -060034 cache_dir=None, empty_sysroot=None, blacklist=None):
Alex Kleina2e42c42019-04-17 16:13:19 -060035 """Helper to build an input message instance."""
Alex Kleinf2674462019-05-16 16:47:24 -060036 formatted_blacklist = []
37 for pkg in blacklist or []:
38 formatted_blacklist.append({'category': pkg.category,
39 'package_name': pkg.package})
40
Alex Kleina2e42c42019-04-17 16:13:19 -060041 return test_pb2.BuildTargetUnitTestRequest(
42 build_target={'name': board}, result_path=result_path,
Alex Kleinfa6ebdc2019-05-10 10:57:31 -060043 chroot={'path': chroot_path, 'cache_dir': cache_dir},
Alex Kleinf2674462019-05-16 16:47:24 -060044 flags={'empty_sysroot': empty_sysroot},
45 package_blacklist=formatted_blacklist,
Alex Kleina2e42c42019-04-17 16:13:19 -060046 )
47
48 def _GetOutput(self):
49 """Helper to get an empty output message instance."""
50 return test_pb2.BuildTargetUnitTestResponse()
51
Alex Klein231d2da2019-07-22 16:44:45 -060052 def testValidateOnly(self):
53 """Sanity check that a validate only call does not execute any logic."""
54 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
55
56 input_msg = self._GetInput(board='board', result_path=self.tempdir)
57 test_controller.BuildTargetUnitTest(input_msg, self._GetOutput(),
58 self.validate_only_config)
59 patch.assert_not_called()
60
Alex Kleina2e42c42019-04-17 16:13:19 -060061 def testNoArgumentFails(self):
62 """Test no arguments fails."""
63 input_msg = self._GetInput()
64 output_msg = self._GetOutput()
65 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060066 test_controller.BuildTargetUnitTest(input_msg, output_msg,
67 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -060068
69 def testNoBuildTargetFails(self):
70 """Test missing build target name fails."""
71 input_msg = self._GetInput(result_path=self.tempdir)
72 output_msg = self._GetOutput()
73 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060074 test_controller.BuildTargetUnitTest(input_msg, output_msg,
75 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -060076
77 def testNoResultPathFails(self):
78 """Test missing result path fails."""
79 # Missing result_path.
80 input_msg = self._GetInput(board='board')
81 output_msg = self._GetOutput()
82 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060083 test_controller.BuildTargetUnitTest(input_msg, output_msg,
84 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -060085
86 def testPackageBuildFailure(self):
87 """Test handling of raised BuildPackageFailure."""
88 tempdir = osutils.TempDir(base_dir=self.tempdir)
89 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
90
91 pkgs = ['cat/pkg', 'foo/bar']
92 expected = [('cat', 'pkg'), ('foo', 'bar')]
Alex Kleina2e42c42019-04-17 16:13:19 -060093
Alex Klein38c7d9e2019-05-08 09:31:19 -060094 result = test_service.BuildTargetUnitTestResult(1, None)
95 result.failed_cpvs = [portage_util.SplitCPV(p, strict=False) for p in pkgs]
96 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -060097
98 input_msg = self._GetInput(board='board', result_path=self.tempdir)
99 output_msg = self._GetOutput()
100
Alex Klein231d2da2019-07-22 16:44:45 -0600101 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
102 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600103
Alex Klein8cb365a2019-05-15 16:24:53 -0600104 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600105 self.assertTrue(output_msg.failed_packages)
106 failed = []
107 for pi in output_msg.failed_packages:
108 failed.append((pi.category, pi.package_name))
Mike Frysinger678735c2019-09-28 18:23:28 -0400109 self.assertCountEqual(expected, failed)
Alex Kleina2e42c42019-04-17 16:13:19 -0600110
111 def testOtherBuildScriptFailure(self):
112 """Test build script failure due to non-package emerge error."""
113 tempdir = osutils.TempDir(base_dir=self.tempdir)
114 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
115
Alex Klein38c7d9e2019-05-08 09:31:19 -0600116 result = test_service.BuildTargetUnitTestResult(1, None)
117 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600118
Alex Kleinf2674462019-05-16 16:47:24 -0600119 pkgs = ['foo/bar', 'cat/pkg']
120 blacklist = [portage_util.SplitCPV(p, strict=False) for p in pkgs]
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600121 input_msg = self._GetInput(board='board', result_path=self.tempdir,
Alex Kleinf2674462019-05-16 16:47:24 -0600122 empty_sysroot=True, blacklist=blacklist)
Alex Kleina2e42c42019-04-17 16:13:19 -0600123 output_msg = self._GetOutput()
124
Alex Klein231d2da2019-07-22 16:44:45 -0600125 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
126 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600127
Alex Klein8cb365a2019-05-15 16:24:53 -0600128 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600129 self.assertFalse(output_msg.failed_packages)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600130
131
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600132class CrosSigningTestTest(cros_test_lib.RunCommandTestCase,
133 api_config.ApiConfigMixin):
134 """CrosSigningTest tests."""
135
136 def testValidateOnly(self):
137 """Sanity check that a validate only call does not execute any logic."""
138 test_controller.CrosSigningTest(None, None, self.validate_only_config)
139 self.assertFalse(self.rc.call_count)
140
141
Michael Mortensenc28d6f12019-10-03 13:34:51 -0600142class SimpleChromeWorkflowTestTest(cros_test_lib.MockTestCase,
143 api_config.ApiConfigMixin):
144 """Test the SimpleChromeWorkflowTest endpoint."""
145
146 @staticmethod
147 def _Output():
148 return test_pb2.SimpleChromeWorkflowTestResponse()
149
150 def _Input(self, sysroot_path=None, build_target=None, chrome_root=None,
151 goma_config=None):
152 proto = test_pb2.SimpleChromeWorkflowTestRequest()
153 if sysroot_path:
154 proto.sysroot.path = sysroot_path
155 if build_target:
156 proto.sysroot.build_target.name = build_target
157 if chrome_root:
158 proto.chrome_root = chrome_root
159 if goma_config:
160 proto.goma_config = goma_config
161 return proto
162
163 def setUp(self):
164 self.chrome_path = 'path/to/chrome'
165 self.sysroot_dir = 'build/board'
166 self.build_target = 'amd64'
167 self.mock_simple_chrome_workflow_test = self.PatchObject(
168 test_service, 'SimpleChromeWorkflowTest')
169
170 def testMissingBuildTarget(self):
171 """Test VmTest dies when build_target not set."""
172 input_proto = self._Input(build_target=None, sysroot_path='/sysroot/dir',
173 chrome_root='/chrome/path')
174 with self.assertRaises(cros_build_lib.DieSystemExit):
175 test_controller.SimpleChromeWorkflowTest(input_proto, None,
176 self.api_config)
177
178 def testMissingSysrootPath(self):
179 """Test VmTest dies when build_target not set."""
180 input_proto = self._Input(build_target='board', sysroot_path=None,
181 chrome_root='/chrome/path')
182 with self.assertRaises(cros_build_lib.DieSystemExit):
183 test_controller.SimpleChromeWorkflowTest(input_proto, None,
184 self.api_config)
185
186 def testMissingChromeRoot(self):
187 """Test VmTest dies when build_target not set."""
188 input_proto = self._Input(build_target='board', sysroot_path='/sysroot/dir',
189 chrome_root=None)
190 with self.assertRaises(cros_build_lib.DieSystemExit):
191 test_controller.SimpleChromeWorkflowTest(input_proto, None,
192 self.api_config)
193
194 def testSimpleChromeWorkflowTest(self):
195 """Call SimpleChromeWorkflowTest with valid args and temp dir."""
196 request = self._Input(sysroot_path='sysroot_path', build_target='board',
197 chrome_root='/path/to/chrome')
198 response = self._Output()
199
200 test_controller.SimpleChromeWorkflowTest(request, response, self.api_config)
201 self.mock_simple_chrome_workflow_test.assert_called()
202
203 def testValidateOnly(self):
204 request = self._Input(sysroot_path='sysroot_path', build_target='board',
205 chrome_root='/path/to/chrome')
206 test_controller.SimpleChromeWorkflowTest(request, self._Output(),
207 self.validate_only_config)
208 self.mock_simple_chrome_workflow_test.assert_not_called()
209
210
Alex Klein231d2da2019-07-22 16:44:45 -0600211class VmTestTest(cros_test_lib.RunCommandTestCase, api_config.ApiConfigMixin):
Evan Hernandez4e388a52019-05-01 12:16:33 -0600212 """Test the VmTest endpoint."""
213
214 def _GetInput(self, **kwargs):
215 values = dict(
216 build_target=common_pb2.BuildTarget(name='target'),
Alex Klein311b8022019-06-05 16:00:07 -0600217 vm_path=common_pb2.Path(path='/path/to/image.bin',
218 location=common_pb2.Path.INSIDE),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600219 test_harness=test_pb2.VmTestRequest.TAST,
220 vm_tests=[test_pb2.VmTestRequest.VmTest(pattern='suite')],
221 ssh_options=test_pb2.VmTestRequest.SshOptions(
Alex Klein231d2da2019-07-22 16:44:45 -0600222 port=1234, private_key_path={'path': '/path/to/id_rsa',
Alex Kleinaa705412019-06-04 15:00:30 -0600223 'location': common_pb2.Path.INSIDE}),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600224 )
225 values.update(kwargs)
226 return test_pb2.VmTestRequest(**values)
227
Alex Klein231d2da2019-07-22 16:44:45 -0600228 def testValidateOnly(self):
229 """Sanity check that a validate only call does not execute any logic."""
230 test_controller.VmTest(self._GetInput(), None, self.validate_only_config)
231 self.assertEqual(0, self.rc.call_count)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600232
233 def testTastAllOptions(self):
234 """Test VmTest for Tast with all options set."""
Alex Klein231d2da2019-07-22 16:44:45 -0600235 test_controller.VmTest(self._GetInput(), None, self.api_config)
236 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700237 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600238 '--board', 'target',
239 '--image-path', '/path/to/image.bin',
240 '--tast', 'suite',
241 '--ssh-port', '1234',
242 '--private-key', '/path/to/id_rsa',
243 ])
244
245 def testAutotestAllOptions(self):
246 """Test VmTest for Autotest with all options set."""
247 input_proto = self._GetInput(test_harness=test_pb2.VmTestRequest.AUTOTEST)
Alex Klein231d2da2019-07-22 16:44:45 -0600248 test_controller.VmTest(input_proto, None, self.api_config)
249 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700250 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600251 '--board', 'target',
252 '--image-path', '/path/to/image.bin',
253 '--autotest', 'suite',
254 '--ssh-port', '1234',
255 '--private-key', '/path/to/id_rsa',
256 '--test_that-args=--whitelist-chrome-crashes',
257 ])
258
259 def testMissingBuildTarget(self):
260 """Test VmTest dies when build_target not set."""
261 input_proto = self._GetInput(build_target=None)
262 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600263 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600264
265 def testMissingVmImage(self):
266 """Test VmTest dies when vm_image not set."""
Alex Klein311b8022019-06-05 16:00:07 -0600267 input_proto = self._GetInput(vm_path=None)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600268 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600269 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600270
271 def testMissingTestHarness(self):
272 """Test VmTest dies when test_harness not specified."""
273 input_proto = self._GetInput(
274 test_harness=test_pb2.VmTestRequest.UNSPECIFIED)
275 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600276 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600277
278 def testMissingVmTests(self):
279 """Test VmTest dies when vm_tests not set."""
280 input_proto = self._GetInput(vm_tests=[])
281 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600282 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600283
284
Alex Klein231d2da2019-07-22 16:44:45 -0600285class MoblabVmTestTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600286 """Test the MoblabVmTest endpoint."""
287
288 @staticmethod
289 def _Payload(path):
290 return test_pb2.MoblabVmTestRequest.Payload(
291 path=common_pb2.Path(path=path))
292
293 @staticmethod
294 def _Output():
295 return test_pb2.MoblabVmTestResponse()
296
297 def _Input(self):
298 return test_pb2.MoblabVmTestRequest(
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600299 chroot=common_pb2.Chroot(path=self.chroot_dir),
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600300 image_payload=self._Payload(self.image_payload_dir),
301 cache_payloads=[self._Payload(self.autotest_payload_dir)])
302
303 def setUp(self):
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600304 self.chroot_dir = '/chroot'
305 self.chroot_tmp_dir = '/chroot/tmp'
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600306 self.image_payload_dir = '/payloads/image'
307 self.autotest_payload_dir = '/payloads/autotest'
308 self.builder = 'moblab-generic-vm/R12-3.4.5-67.890'
309 self.image_cache_dir = '/mnt/moblab/cache'
310 self.image_mount_dir = '/mnt/image'
311
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600312 self.PatchObject(chroot_lib.Chroot, 'tempdir', osutils.TempDir)
Evan Hernandez655e8042019-06-13 12:50:44 -0600313
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600314 self.mock_create_moblab_vms = self.PatchObject(
315 test_service, 'CreateMoblabVm')
316 self.mock_prepare_moblab_vm_image_cache = self.PatchObject(
317 test_service, 'PrepareMoblabVmImageCache',
318 return_value=self.image_cache_dir)
319 self.mock_run_moblab_vm_tests = self.PatchObject(
320 test_service, 'RunMoblabVmTest')
321 self.mock_validate_moblab_vm_tests = self.PatchObject(
322 test_service, 'ValidateMoblabVmTest')
323
324 @contextlib.contextmanager
Alex Klein38c7d9e2019-05-08 09:31:19 -0600325 def MockLoopbackPartitions(*_args, **_kwargs):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600326 mount = mock.MagicMock()
Evan Hernandez40ee7452019-06-13 12:51:43 -0600327 mount.Mount.return_value = [self.image_mount_dir]
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600328 yield mount
Alex Klein231d2da2019-07-22 16:44:45 -0600329
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600330 self.PatchObject(image_lib, 'LoopbackPartitions', MockLoopbackPartitions)
331
Alex Klein231d2da2019-07-22 16:44:45 -0600332 def testValidateOnly(self):
333 """Sanity check that a validate only call does not execute any logic."""
334 test_controller.MoblabVmTest(self._Input(), self._Output(),
335 self.validate_only_config)
336 self.mock_create_moblab_vms.assert_not_called()
337
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600338 def testImageContainsBuilder(self):
339 """MoblabVmTest calls service with correct args."""
340 request = self._Input()
341 response = self._Output()
342
343 self.PatchObject(
Mike Frysingere652ba12019-09-08 00:57:43 -0400344 key_value_store, 'LoadFile',
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600345 return_value={cros_set_lsb_release.LSB_KEY_BUILDER_PATH: self.builder})
346
Alex Klein231d2da2019-07-22 16:44:45 -0600347 test_controller.MoblabVmTest(request, response, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600348
349 self.assertEqual(
350 self.mock_create_moblab_vms.call_args_list,
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600351 [mock.call(mock.ANY, self.chroot_dir, self.image_payload_dir)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600352 self.assertEqual(
353 self.mock_prepare_moblab_vm_image_cache.call_args_list,
354 [mock.call(mock.ANY, self.builder, [self.autotest_payload_dir])])
355 self.assertEqual(
356 self.mock_run_moblab_vm_tests.call_args_list,
Evan Hernandez655e8042019-06-13 12:50:44 -0600357 [mock.call(mock.ANY, mock.ANY, self.builder, self.image_cache_dir,
358 mock.ANY)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600359 self.assertEqual(
360 self.mock_validate_moblab_vm_tests.call_args_list,
361 [mock.call(mock.ANY)])
362
363 def testImageMissingBuilder(self):
364 """MoblabVmTest dies when builder path not found in lsb-release."""
365 request = self._Input()
366 response = self._Output()
367
Mike Frysingere652ba12019-09-08 00:57:43 -0400368 self.PatchObject(key_value_store, 'LoadFile', return_value={})
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600369
370 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600371 test_controller.MoblabVmTest(request, response, self.api_config)