blob: 4a4caaf21856244f7ba4da35c8c51ea77bc28d4e [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
Alex Kleina2e42c42019-04-17 16:13:19 -060026
27
Alex Klein231d2da2019-07-22 16:44:45 -060028class BuildTargetUnitTestTest(cros_test_lib.MockTempDirTestCase,
29 api_config.ApiConfigMixin):
Alex Kleina2e42c42019-04-17 16:13:19 -060030 """Tests for the UnitTest function."""
31
32 def _GetInput(self, board=None, result_path=None, chroot_path=None,
Alex Kleinf2674462019-05-16 16:47:24 -060033 cache_dir=None, empty_sysroot=None, blacklist=None):
Alex Kleina2e42c42019-04-17 16:13:19 -060034 """Helper to build an input message instance."""
Alex Kleinf2674462019-05-16 16:47:24 -060035 formatted_blacklist = []
36 for pkg in blacklist or []:
37 formatted_blacklist.append({'category': pkg.category,
38 'package_name': pkg.package})
39
Alex Kleina2e42c42019-04-17 16:13:19 -060040 return test_pb2.BuildTargetUnitTestRequest(
41 build_target={'name': board}, result_path=result_path,
Alex Kleinfa6ebdc2019-05-10 10:57:31 -060042 chroot={'path': chroot_path, 'cache_dir': cache_dir},
Alex Kleinf2674462019-05-16 16:47:24 -060043 flags={'empty_sysroot': empty_sysroot},
44 package_blacklist=formatted_blacklist,
Alex Kleina2e42c42019-04-17 16:13:19 -060045 )
46
47 def _GetOutput(self):
48 """Helper to get an empty output message instance."""
49 return test_pb2.BuildTargetUnitTestResponse()
50
Alex Klein231d2da2019-07-22 16:44:45 -060051 def testValidateOnly(self):
52 """Sanity check that a validate only call does not execute any logic."""
53 patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
54
55 input_msg = self._GetInput(board='board', result_path=self.tempdir)
56 test_controller.BuildTargetUnitTest(input_msg, self._GetOutput(),
57 self.validate_only_config)
58 patch.assert_not_called()
59
Alex Kleina2e42c42019-04-17 16:13:19 -060060 def testNoArgumentFails(self):
61 """Test no arguments fails."""
62 input_msg = self._GetInput()
63 output_msg = self._GetOutput()
64 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060065 test_controller.BuildTargetUnitTest(input_msg, output_msg,
66 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -060067
68 def testNoBuildTargetFails(self):
69 """Test missing build target name fails."""
70 input_msg = self._GetInput(result_path=self.tempdir)
71 output_msg = self._GetOutput()
72 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060073 test_controller.BuildTargetUnitTest(input_msg, output_msg,
74 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -060075
76 def testNoResultPathFails(self):
77 """Test missing result path fails."""
78 # Missing result_path.
79 input_msg = self._GetInput(board='board')
80 output_msg = self._GetOutput()
81 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -060082 test_controller.BuildTargetUnitTest(input_msg, output_msg,
83 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -060084
85 def testPackageBuildFailure(self):
86 """Test handling of raised BuildPackageFailure."""
87 tempdir = osutils.TempDir(base_dir=self.tempdir)
88 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
89
90 pkgs = ['cat/pkg', 'foo/bar']
91 expected = [('cat', 'pkg'), ('foo', 'bar')]
Alex Kleina2e42c42019-04-17 16:13:19 -060092
Alex Klein38c7d9e2019-05-08 09:31:19 -060093 result = test_service.BuildTargetUnitTestResult(1, None)
94 result.failed_cpvs = [portage_util.SplitCPV(p, strict=False) for p in pkgs]
95 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -060096
97 input_msg = self._GetInput(board='board', result_path=self.tempdir)
98 output_msg = self._GetOutput()
99
Alex Klein231d2da2019-07-22 16:44:45 -0600100 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
101 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600102
Alex Klein8cb365a2019-05-15 16:24:53 -0600103 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600104 self.assertTrue(output_msg.failed_packages)
105 failed = []
106 for pi in output_msg.failed_packages:
107 failed.append((pi.category, pi.package_name))
108 self.assertItemsEqual(expected, failed)
109
110 def testOtherBuildScriptFailure(self):
111 """Test build script failure due to non-package emerge error."""
112 tempdir = osutils.TempDir(base_dir=self.tempdir)
113 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
114
Alex Klein38c7d9e2019-05-08 09:31:19 -0600115 result = test_service.BuildTargetUnitTestResult(1, None)
116 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600117
Alex Kleinf2674462019-05-16 16:47:24 -0600118 pkgs = ['foo/bar', 'cat/pkg']
119 blacklist = [portage_util.SplitCPV(p, strict=False) for p in pkgs]
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600120 input_msg = self._GetInput(board='board', result_path=self.tempdir,
Alex Kleinf2674462019-05-16 16:47:24 -0600121 empty_sysroot=True, blacklist=blacklist)
Alex Kleina2e42c42019-04-17 16:13:19 -0600122 output_msg = self._GetOutput()
123
Alex Klein231d2da2019-07-22 16:44:45 -0600124 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
125 self.api_config)
Alex Kleina2e42c42019-04-17 16:13:19 -0600126
Alex Klein8cb365a2019-05-15 16:24:53 -0600127 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600128 self.assertFalse(output_msg.failed_packages)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600129
130
Alex Klein4bc8f4f2019-08-16 14:53:30 -0600131class CrosSigningTestTest(cros_test_lib.RunCommandTestCase,
132 api_config.ApiConfigMixin):
133 """CrosSigningTest tests."""
134
135 def testValidateOnly(self):
136 """Sanity check that a validate only call does not execute any logic."""
137 test_controller.CrosSigningTest(None, None, self.validate_only_config)
138 self.assertFalse(self.rc.call_count)
139
140
Alex Klein231d2da2019-07-22 16:44:45 -0600141class VmTestTest(cros_test_lib.RunCommandTestCase, api_config.ApiConfigMixin):
Evan Hernandez4e388a52019-05-01 12:16:33 -0600142 """Test the VmTest endpoint."""
143
144 def _GetInput(self, **kwargs):
145 values = dict(
146 build_target=common_pb2.BuildTarget(name='target'),
Alex Klein311b8022019-06-05 16:00:07 -0600147 vm_path=common_pb2.Path(path='/path/to/image.bin',
148 location=common_pb2.Path.INSIDE),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600149 test_harness=test_pb2.VmTestRequest.TAST,
150 vm_tests=[test_pb2.VmTestRequest.VmTest(pattern='suite')],
151 ssh_options=test_pb2.VmTestRequest.SshOptions(
Alex Klein231d2da2019-07-22 16:44:45 -0600152 port=1234, private_key_path={'path': '/path/to/id_rsa',
Alex Kleinaa705412019-06-04 15:00:30 -0600153 'location': common_pb2.Path.INSIDE}),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600154 )
155 values.update(kwargs)
156 return test_pb2.VmTestRequest(**values)
157
Alex Klein231d2da2019-07-22 16:44:45 -0600158 def testValidateOnly(self):
159 """Sanity check that a validate only call does not execute any logic."""
160 test_controller.VmTest(self._GetInput(), None, self.validate_only_config)
161 self.assertEqual(0, self.rc.call_count)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600162
163 def testTastAllOptions(self):
164 """Test VmTest for Tast with all options set."""
Alex Klein231d2da2019-07-22 16:44:45 -0600165 test_controller.VmTest(self._GetInput(), None, self.api_config)
166 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700167 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600168 '--board', 'target',
169 '--image-path', '/path/to/image.bin',
170 '--tast', 'suite',
171 '--ssh-port', '1234',
172 '--private-key', '/path/to/id_rsa',
173 ])
174
175 def testAutotestAllOptions(self):
176 """Test VmTest for Autotest with all options set."""
177 input_proto = self._GetInput(test_harness=test_pb2.VmTestRequest.AUTOTEST)
Alex Klein231d2da2019-07-22 16:44:45 -0600178 test_controller.VmTest(input_proto, None, self.api_config)
179 self.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700180 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600181 '--board', 'target',
182 '--image-path', '/path/to/image.bin',
183 '--autotest', 'suite',
184 '--ssh-port', '1234',
185 '--private-key', '/path/to/id_rsa',
186 '--test_that-args=--whitelist-chrome-crashes',
187 ])
188
189 def testMissingBuildTarget(self):
190 """Test VmTest dies when build_target not set."""
191 input_proto = self._GetInput(build_target=None)
192 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600193 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600194
195 def testMissingVmImage(self):
196 """Test VmTest dies when vm_image not set."""
Alex Klein311b8022019-06-05 16:00:07 -0600197 input_proto = self._GetInput(vm_path=None)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600198 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600199 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600200
201 def testMissingTestHarness(self):
202 """Test VmTest dies when test_harness not specified."""
203 input_proto = self._GetInput(
204 test_harness=test_pb2.VmTestRequest.UNSPECIFIED)
205 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600206 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600207
208 def testMissingVmTests(self):
209 """Test VmTest dies when vm_tests not set."""
210 input_proto = self._GetInput(vm_tests=[])
211 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600212 test_controller.VmTest(input_proto, None, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600213
214
Alex Klein231d2da2019-07-22 16:44:45 -0600215class MoblabVmTestTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600216 """Test the MoblabVmTest endpoint."""
217
218 @staticmethod
219 def _Payload(path):
220 return test_pb2.MoblabVmTestRequest.Payload(
221 path=common_pb2.Path(path=path))
222
223 @staticmethod
224 def _Output():
225 return test_pb2.MoblabVmTestResponse()
226
227 def _Input(self):
228 return test_pb2.MoblabVmTestRequest(
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600229 chroot=common_pb2.Chroot(path=self.chroot_dir),
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600230 image_payload=self._Payload(self.image_payload_dir),
231 cache_payloads=[self._Payload(self.autotest_payload_dir)])
232
233 def setUp(self):
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600234 self.chroot_dir = '/chroot'
235 self.chroot_tmp_dir = '/chroot/tmp'
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600236 self.image_payload_dir = '/payloads/image'
237 self.autotest_payload_dir = '/payloads/autotest'
238 self.builder = 'moblab-generic-vm/R12-3.4.5-67.890'
239 self.image_cache_dir = '/mnt/moblab/cache'
240 self.image_mount_dir = '/mnt/image'
241
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600242 self.PatchObject(chroot_lib.Chroot, 'tempdir', osutils.TempDir)
Evan Hernandez655e8042019-06-13 12:50:44 -0600243
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600244 self.mock_create_moblab_vms = self.PatchObject(
245 test_service, 'CreateMoblabVm')
246 self.mock_prepare_moblab_vm_image_cache = self.PatchObject(
247 test_service, 'PrepareMoblabVmImageCache',
248 return_value=self.image_cache_dir)
249 self.mock_run_moblab_vm_tests = self.PatchObject(
250 test_service, 'RunMoblabVmTest')
251 self.mock_validate_moblab_vm_tests = self.PatchObject(
252 test_service, 'ValidateMoblabVmTest')
253
254 @contextlib.contextmanager
Alex Klein38c7d9e2019-05-08 09:31:19 -0600255 def MockLoopbackPartitions(*_args, **_kwargs):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600256 mount = mock.MagicMock()
Evan Hernandez40ee7452019-06-13 12:51:43 -0600257 mount.Mount.return_value = [self.image_mount_dir]
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600258 yield mount
Alex Klein231d2da2019-07-22 16:44:45 -0600259
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600260 self.PatchObject(image_lib, 'LoopbackPartitions', MockLoopbackPartitions)
261
Alex Klein231d2da2019-07-22 16:44:45 -0600262 def testValidateOnly(self):
263 """Sanity check that a validate only call does not execute any logic."""
264 test_controller.MoblabVmTest(self._Input(), self._Output(),
265 self.validate_only_config)
266 self.mock_create_moblab_vms.assert_not_called()
267
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600268 def testImageContainsBuilder(self):
269 """MoblabVmTest calls service with correct args."""
270 request = self._Input()
271 response = self._Output()
272
273 self.PatchObject(
274 cros_build_lib, 'LoadKeyValueFile',
275 return_value={cros_set_lsb_release.LSB_KEY_BUILDER_PATH: self.builder})
276
Alex Klein231d2da2019-07-22 16:44:45 -0600277 test_controller.MoblabVmTest(request, response, self.api_config)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600278
279 self.assertEqual(
280 self.mock_create_moblab_vms.call_args_list,
Evan Hernandeze1e05d32019-07-19 12:32:18 -0600281 [mock.call(mock.ANY, self.chroot_dir, self.image_payload_dir)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600282 self.assertEqual(
283 self.mock_prepare_moblab_vm_image_cache.call_args_list,
284 [mock.call(mock.ANY, self.builder, [self.autotest_payload_dir])])
285 self.assertEqual(
286 self.mock_run_moblab_vm_tests.call_args_list,
Evan Hernandez655e8042019-06-13 12:50:44 -0600287 [mock.call(mock.ANY, mock.ANY, self.builder, self.image_cache_dir,
288 mock.ANY)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600289 self.assertEqual(
290 self.mock_validate_moblab_vm_tests.call_args_list,
291 [mock.call(mock.ANY)])
292
293 def testImageMissingBuilder(self):
294 """MoblabVmTest dies when builder path not found in lsb-release."""
295 request = self._Input()
296 response = self._Output()
297
298 self.PatchObject(cros_build_lib, 'LoadKeyValueFile', return_value={})
299
300 with self.assertRaises(cros_build_lib.DieSystemExit):
Alex Klein231d2da2019-07-22 16:44:45 -0600301 test_controller.MoblabVmTest(request, response, self.api_config)