blob: d1b6302d93f7a8de526a74ac499f612465139704 [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 Klein8cb365a2019-05-15 16:24:53 -060013from chromite.api import controller
Evan Hernandez655e8042019-06-13 12:50:44 -060014from chromite.api.controller import controller_util
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
Alex Kleina2e42c42019-04-17 16:13:19 -060018from chromite.lib import cros_build_lib
19from chromite.lib import cros_test_lib
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060020from chromite.lib import image_lib
Alex Kleina2e42c42019-04-17 16:13:19 -060021from chromite.lib import osutils
22from chromite.lib import portage_util
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -060023from chromite.scripts import cros_set_lsb_release
24from chromite.service import test as test_service
Alex Kleina2e42c42019-04-17 16:13:19 -060025
26
Evan Hernandez4e388a52019-05-01 12:16:33 -060027class BuildTargetUnitTestTest(cros_test_lib.MockTempDirTestCase):
Alex Kleina2e42c42019-04-17 16:13:19 -060028 """Tests for the UnitTest function."""
29
30 def _GetInput(self, board=None, result_path=None, chroot_path=None,
Alex Kleinf2674462019-05-16 16:47:24 -060031 cache_dir=None, empty_sysroot=None, blacklist=None):
Alex Kleina2e42c42019-04-17 16:13:19 -060032 """Helper to build an input message instance."""
Alex Kleinf2674462019-05-16 16:47:24 -060033 formatted_blacklist = []
34 for pkg in blacklist or []:
35 formatted_blacklist.append({'category': pkg.category,
36 'package_name': pkg.package})
37
Alex Kleina2e42c42019-04-17 16:13:19 -060038 return test_pb2.BuildTargetUnitTestRequest(
39 build_target={'name': board}, result_path=result_path,
Alex Kleinfa6ebdc2019-05-10 10:57:31 -060040 chroot={'path': chroot_path, 'cache_dir': cache_dir},
Alex Kleinf2674462019-05-16 16:47:24 -060041 flags={'empty_sysroot': empty_sysroot},
42 package_blacklist=formatted_blacklist,
Alex Kleina2e42c42019-04-17 16:13:19 -060043 )
44
45 def _GetOutput(self):
46 """Helper to get an empty output message instance."""
47 return test_pb2.BuildTargetUnitTestResponse()
48
49 def testNoArgumentFails(self):
50 """Test no arguments fails."""
51 input_msg = self._GetInput()
52 output_msg = self._GetOutput()
53 with self.assertRaises(cros_build_lib.DieSystemExit):
54 test_controller.BuildTargetUnitTest(input_msg, output_msg)
55
56 def testNoBuildTargetFails(self):
57 """Test missing build target name fails."""
58 input_msg = self._GetInput(result_path=self.tempdir)
59 output_msg = self._GetOutput()
60 with self.assertRaises(cros_build_lib.DieSystemExit):
61 test_controller.BuildTargetUnitTest(input_msg, output_msg)
62
63 def testNoResultPathFails(self):
64 """Test missing result path fails."""
65 # Missing result_path.
66 input_msg = self._GetInput(board='board')
67 output_msg = self._GetOutput()
68 with self.assertRaises(cros_build_lib.DieSystemExit):
69 test_controller.BuildTargetUnitTest(input_msg, output_msg)
70
71 def testPackageBuildFailure(self):
72 """Test handling of raised BuildPackageFailure."""
73 tempdir = osutils.TempDir(base_dir=self.tempdir)
74 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
75
76 pkgs = ['cat/pkg', 'foo/bar']
77 expected = [('cat', 'pkg'), ('foo', 'bar')]
Alex Kleina2e42c42019-04-17 16:13:19 -060078
Alex Klein38c7d9e2019-05-08 09:31:19 -060079 result = test_service.BuildTargetUnitTestResult(1, None)
80 result.failed_cpvs = [portage_util.SplitCPV(p, strict=False) for p in pkgs]
81 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -060082
83 input_msg = self._GetInput(board='board', result_path=self.tempdir)
84 output_msg = self._GetOutput()
85
86 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg)
87
Alex Klein8cb365a2019-05-15 16:24:53 -060088 self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -060089 self.assertTrue(output_msg.failed_packages)
90 failed = []
91 for pi in output_msg.failed_packages:
92 failed.append((pi.category, pi.package_name))
93 self.assertItemsEqual(expected, failed)
94
95 def testOtherBuildScriptFailure(self):
96 """Test build script failure due to non-package emerge error."""
97 tempdir = osutils.TempDir(base_dir=self.tempdir)
98 self.PatchObject(osutils, 'TempDir', return_value=tempdir)
99
Alex Klein38c7d9e2019-05-08 09:31:19 -0600100 result = test_service.BuildTargetUnitTestResult(1, None)
101 self.PatchObject(test_service, 'BuildTargetUnitTest', return_value=result)
Alex Kleina2e42c42019-04-17 16:13:19 -0600102
Alex Kleinf2674462019-05-16 16:47:24 -0600103 pkgs = ['foo/bar', 'cat/pkg']
104 blacklist = [portage_util.SplitCPV(p, strict=False) for p in pkgs]
Alex Kleinfa6ebdc2019-05-10 10:57:31 -0600105 input_msg = self._GetInput(board='board', result_path=self.tempdir,
Alex Kleinf2674462019-05-16 16:47:24 -0600106 empty_sysroot=True, blacklist=blacklist)
Alex Kleina2e42c42019-04-17 16:13:19 -0600107 output_msg = self._GetOutput()
108
109 rc = test_controller.BuildTargetUnitTest(input_msg, output_msg)
110
Alex Klein8cb365a2019-05-15 16:24:53 -0600111 self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
Alex Kleina2e42c42019-04-17 16:13:19 -0600112 self.assertFalse(output_msg.failed_packages)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600113
114
115class VmTestTest(cros_test_lib.MockTestCase):
116 """Test the VmTest endpoint."""
117
118 def _GetInput(self, **kwargs):
119 values = dict(
120 build_target=common_pb2.BuildTarget(name='target'),
Alex Klein311b8022019-06-05 16:00:07 -0600121 vm_path=common_pb2.Path(path='/path/to/image.bin',
122 location=common_pb2.Path.INSIDE),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600123 test_harness=test_pb2.VmTestRequest.TAST,
124 vm_tests=[test_pb2.VmTestRequest.VmTest(pattern='suite')],
125 ssh_options=test_pb2.VmTestRequest.SshOptions(
Alex Kleinaa705412019-06-04 15:00:30 -0600126 port=1234, private_key_path={'path':'/path/to/id_rsa',
127 'location': common_pb2.Path.INSIDE}),
Evan Hernandez4e388a52019-05-01 12:16:33 -0600128 )
129 values.update(kwargs)
130 return test_pb2.VmTestRequest(**values)
131
132 def setUp(self):
133 self.rc_mock = cros_test_lib.RunCommandMock()
134 self.rc_mock.SetDefaultCmdResult()
135 self.StartPatcher(self.rc_mock)
136
137 def testTastAllOptions(self):
138 """Test VmTest for Tast with all options set."""
139 test_controller.VmTest(self._GetInput(), None)
140 self.rc_mock.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700141 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600142 '--board', 'target',
143 '--image-path', '/path/to/image.bin',
144 '--tast', 'suite',
145 '--ssh-port', '1234',
146 '--private-key', '/path/to/id_rsa',
147 ])
148
149 def testAutotestAllOptions(self):
150 """Test VmTest for Autotest with all options set."""
151 input_proto = self._GetInput(test_harness=test_pb2.VmTestRequest.AUTOTEST)
152 test_controller.VmTest(input_proto, None)
153 self.rc_mock.assertCommandContains([
Achuith Bhandarkara9e9c3d2019-05-22 13:56:11 -0700154 'cros_run_test', '--debug', '--no-display', '--copy-on-write',
Evan Hernandez4e388a52019-05-01 12:16:33 -0600155 '--board', 'target',
156 '--image-path', '/path/to/image.bin',
157 '--autotest', 'suite',
158 '--ssh-port', '1234',
159 '--private-key', '/path/to/id_rsa',
160 '--test_that-args=--whitelist-chrome-crashes',
161 ])
162
163 def testMissingBuildTarget(self):
164 """Test VmTest dies when build_target not set."""
165 input_proto = self._GetInput(build_target=None)
166 with self.assertRaises(cros_build_lib.DieSystemExit):
167 test_controller.VmTest(input_proto, None)
168
169 def testMissingVmImage(self):
170 """Test VmTest dies when vm_image not set."""
Alex Klein311b8022019-06-05 16:00:07 -0600171 input_proto = self._GetInput(vm_path=None)
Evan Hernandez4e388a52019-05-01 12:16:33 -0600172 with self.assertRaises(cros_build_lib.DieSystemExit):
173 test_controller.VmTest(input_proto, None)
174
175 def testMissingTestHarness(self):
176 """Test VmTest dies when test_harness not specified."""
177 input_proto = self._GetInput(
178 test_harness=test_pb2.VmTestRequest.UNSPECIFIED)
179 with self.assertRaises(cros_build_lib.DieSystemExit):
180 test_controller.VmTest(input_proto, None)
181
182 def testMissingVmTests(self):
183 """Test VmTest dies when vm_tests not set."""
184 input_proto = self._GetInput(vm_tests=[])
185 with self.assertRaises(cros_build_lib.DieSystemExit):
186 test_controller.VmTest(input_proto, None)
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600187
188
189class MoblabVmTestTest(cros_test_lib.MockTestCase):
190 """Test the MoblabVmTest endpoint."""
191
192 @staticmethod
193 def _Payload(path):
194 return test_pb2.MoblabVmTestRequest.Payload(
195 path=common_pb2.Path(path=path))
196
197 @staticmethod
198 def _Output():
199 return test_pb2.MoblabVmTestResponse()
200
201 def _Input(self):
202 return test_pb2.MoblabVmTestRequest(
Evan Hernandez655e8042019-06-13 12:50:44 -0600203 chroot=common_pb2.Chroot(path='path/to/chroot'),
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600204 image_payload=self._Payload(self.image_payload_dir),
205 cache_payloads=[self._Payload(self.autotest_payload_dir)])
206
207 def setUp(self):
208 self.image_payload_dir = '/payloads/image'
209 self.autotest_payload_dir = '/payloads/autotest'
210 self.builder = 'moblab-generic-vm/R12-3.4.5-67.890'
211 self.image_cache_dir = '/mnt/moblab/cache'
212 self.image_mount_dir = '/mnt/image'
213
Evan Hernandez655e8042019-06-13 12:50:44 -0600214 self.PatchObject(controller_util, 'ParseChroot')
215
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600216 self.mock_create_moblab_vms = self.PatchObject(
217 test_service, 'CreateMoblabVm')
218 self.mock_prepare_moblab_vm_image_cache = self.PatchObject(
219 test_service, 'PrepareMoblabVmImageCache',
220 return_value=self.image_cache_dir)
221 self.mock_run_moblab_vm_tests = self.PatchObject(
222 test_service, 'RunMoblabVmTest')
223 self.mock_validate_moblab_vm_tests = self.PatchObject(
224 test_service, 'ValidateMoblabVmTest')
225
226 @contextlib.contextmanager
Alex Klein38c7d9e2019-05-08 09:31:19 -0600227 def MockLoopbackPartitions(*_args, **_kwargs):
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600228 mount = mock.MagicMock()
Evan Hernandez40ee7452019-06-13 12:51:43 -0600229 mount.Mount.return_value = [self.image_mount_dir]
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600230 yield mount
231 self.PatchObject(image_lib, 'LoopbackPartitions', MockLoopbackPartitions)
232
233 def testImageContainsBuilder(self):
234 """MoblabVmTest calls service with correct args."""
235 request = self._Input()
236 response = self._Output()
237
238 self.PatchObject(
239 cros_build_lib, 'LoadKeyValueFile',
240 return_value={cros_set_lsb_release.LSB_KEY_BUILDER_PATH: self.builder})
241
242 test_controller.MoblabVmTest(request, response)
243
244 self.assertEqual(
245 self.mock_create_moblab_vms.call_args_list,
246 [mock.call(mock.ANY, self.image_payload_dir)])
247 self.assertEqual(
248 self.mock_prepare_moblab_vm_image_cache.call_args_list,
249 [mock.call(mock.ANY, self.builder, [self.autotest_payload_dir])])
250 self.assertEqual(
251 self.mock_run_moblab_vm_tests.call_args_list,
Evan Hernandez655e8042019-06-13 12:50:44 -0600252 [mock.call(mock.ANY, mock.ANY, self.builder, self.image_cache_dir,
253 mock.ANY)])
Evan Hernandezdc3f0bb2019-06-06 12:46:52 -0600254 self.assertEqual(
255 self.mock_validate_moblab_vm_tests.call_args_list,
256 [mock.call(mock.ANY)])
257
258 def testImageMissingBuilder(self):
259 """MoblabVmTest dies when builder path not found in lsb-release."""
260 request = self._Input()
261 response = self._Output()
262
263 self.PatchObject(cros_build_lib, 'LoadKeyValueFile', return_value={})
264
265 with self.assertRaises(cros_build_lib.DieSystemExit):
266 test_controller.MoblabVmTest(request, response)