blob: 580ab847478bf01016f4618cd9198705573593d0 [file] [log] [blame]
Evan Hernandezf388cbf2019-04-01 11:15:23 -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"""Unittests for Artifacts operations."""
7
8from __future__ import print_function
9
10import mock
11import os
12
13from chromite.api.controller import artifacts
14from chromite.api.gen.chromite.api import artifacts_pb2
15from chromite.cbuildbot import commands
Alex Klein6504eca2019-04-18 15:37:56 -060016from chromite.cbuildbot.stages import vm_test_stages
Evan Hernandezf388cbf2019-04-01 11:15:23 -060017from chromite.lib import constants
18from chromite.lib import cros_build_lib
19from chromite.lib import cros_test_lib
20from chromite.lib import osutils
21
22
23class BundleTestCase(cros_test_lib.MockTestCase):
24 """Basic setup for all artifacts unittests."""
25
26 def setUp(self):
27 self.input_proto = artifacts_pb2.BundleRequest()
28 self.input_proto.build_target.name = 'target'
29 self.input_proto.output_dir = '/tmp/artifacts'
30 self.output_proto = artifacts_pb2.BundleResponse()
31
32 self.PatchObject(constants, 'SOURCE_ROOT', new='/cros')
33
34
Evan Hernandez9f125ac2019-04-08 17:18:47 -060035class BundleImageZipTest(BundleTestCase):
36 """Unittests for BundleImageZip."""
37
38 def testBundleImageZip(self):
39 """BundleImageZip calls cbuildbot/commands with correct args."""
40 build_image_zip = self.PatchObject(
41 commands, 'BuildImageZip', return_value='image.zip')
42 self.PatchObject(os.path, 'exists', return_value=True)
43 artifacts.BundleImageZip(self.input_proto, self.output_proto)
44 self.assertEqual(
45 [artifact.path for artifact in self.output_proto.artifacts],
46 ['/tmp/artifacts/image.zip'])
47 self.assertEqual(
48 build_image_zip.call_args_list,
49 [mock.call('/tmp/artifacts', '/cros/src/build/images/target/latest')])
50
51 def testBundleImageZipNoImageDir(self):
52 """BundleImageZip dies when image dir does not exist."""
53 self.PatchObject(os.path, 'exists', return_value=False)
54 with self.assertRaises(cros_build_lib.DieSystemExit):
55 artifacts.BundleImageZip(self.input_proto, self.output_proto)
56
57
Evan Hernandezf388cbf2019-04-01 11:15:23 -060058class BundleAutotestFilesTest(BundleTestCase):
59 """Unittests for BundleAutotestFiles."""
60
61 def testBundleAutotestFiles(self):
62 """BundleAutotestFiles calls cbuildbot/commands with correct args."""
63 build_autotest_tarballs = self.PatchObject(
64 commands,
65 'BuildAutotestTarballsForHWTest',
66 return_value=[
67 '/tmp/artifacts/autotest-a.tar.gz',
68 '/tmp/artifacts/autotest-b.tar.gz',
69 ])
70 artifacts.BundleAutotestFiles(self.input_proto, self.output_proto)
71 self.assertItemsEqual([
72 artifact.path for artifact in self.output_proto.artifacts
73 ], ['/tmp/artifacts/autotest-a.tar.gz', '/tmp/artifacts/autotest-b.tar.gz'])
74 self.assertEqual(build_autotest_tarballs.call_args_list, [
Evan Hernandez36589c62019-04-05 18:14:42 -060075 mock.call('/cros', '/cros/chroot/build/target/usr/local/build',
76 '/tmp/artifacts')
Evan Hernandezf388cbf2019-04-01 11:15:23 -060077 ])
78
79
80class BundleTastFilesTest(BundleTestCase):
81 """Unittests for BundleTastFiles."""
82
83 def testBundleTastFiles(self):
84 """BundleTastFiles calls cbuildbot/commands with correct args."""
85 build_tast_bundle_tarball = self.PatchObject(
86 commands,
87 'BuildTastBundleTarball',
88 return_value='/tmp/artifacts/tast.tar.gz')
89 artifacts.BundleTastFiles(self.input_proto, self.output_proto)
90 self.assertEqual(
91 [artifact.path for artifact in self.output_proto.artifacts],
92 ['/tmp/artifacts/tast.tar.gz'])
93 self.assertEqual(build_tast_bundle_tarball.call_args_list, [
94 mock.call('/cros', '/cros/chroot/build/target/build', '/tmp/artifacts')
95 ])
96
Evan Hernandez9a5d3122019-04-09 10:51:23 -060097 def testBundleTastFilesNoLogs(self):
98 """BundleTasteFiles dies when no tast files found."""
99 self.PatchObject(commands, 'BuildTastBundleTarball',
100 return_value=None)
101 with self.assertRaises(cros_build_lib.DieSystemExit):
102 artifacts.BundleTastFiles(self.input_proto, self.output_proto)
103
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600104
105class BundlePinnedGuestImagesTest(BundleTestCase):
106 """Unittests for BundlePinnedGuestImages."""
107
108 def testBundlePinnedGuestImages(self):
109 """BundlePinnedGuestImages calls cbuildbot/commands with correct args."""
110 build_pinned_guest_images_tarball = self.PatchObject(
111 commands,
112 'BuildPinnedGuestImagesTarball',
113 return_value='pinned-guest-images.tar.gz')
114 artifacts.BundlePinnedGuestImages(self.input_proto, self.output_proto)
115 self.assertEqual(
116 [artifact.path for artifact in self.output_proto.artifacts],
117 ['/tmp/artifacts/pinned-guest-images.tar.gz'])
118 self.assertEqual(build_pinned_guest_images_tarball.call_args_list,
119 [mock.call('/cros', 'target', '/tmp/artifacts')])
120
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600121 def testBundlePinnedGuestImagesNoLogs(self):
Evan Hernandezde445982019-04-22 13:42:34 -0600122 """BundlePinnedGuestImages does not die when no pinned images found."""
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600123 self.PatchObject(commands, 'BuildPinnedGuestImagesTarball',
124 return_value=None)
Evan Hernandezde445982019-04-22 13:42:34 -0600125 artifacts.BundlePinnedGuestImages(self.input_proto, self.output_proto)
126 self.assertFalse(self.output_proto.artifacts)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600127
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600128
129class BundleFirmwareTest(BundleTestCase):
130 """Unittests for BundleFirmware."""
131
132 def testBundleFirmware(self):
133 """BundleFirmware calls cbuildbot/commands with correct args."""
134 build_firmware_archive = self.PatchObject(
135 commands, 'BuildFirmwareArchive', return_value='firmware.tar.gz')
136 artifacts.BundleFirmware(self.input_proto, self.output_proto)
137 self.assertEqual(
138 [artifact.path for artifact in self.output_proto.artifacts],
139 ['/tmp/artifacts/firmware.tar.gz'])
140 self.assertEqual(build_firmware_archive.call_args_list,
141 [mock.call('/cros', 'target', '/tmp/artifacts')])
142
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600143 def testBundleFirmwareNoLogs(self):
144 """BundleFirmware dies when no firmware found."""
145 self.PatchObject(commands, 'BuildFirmwareArchive', return_value=None)
146 with self.assertRaises(cros_build_lib.DieSystemExit):
147 artifacts.BundleFirmware(self.input_proto, self.output_proto)
148
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600149
150class BundleEbuildLogsTest(BundleTestCase):
151 """Unittests for BundleEbuildLogs."""
152
153 def testBundleEbuildLogs(self):
154 """BundleEbuildLogs calls cbuildbot/commands with correct args."""
155 build_ebuild_logs_tarball = self.PatchObject(
156 commands, 'BuildEbuildLogsTarball', return_value='ebuild-logs.tar.gz')
157 artifacts.BundleEbuildLogs(self.input_proto, self.output_proto)
158 self.assertEqual(
159 [artifact.path for artifact in self.output_proto.artifacts],
160 ['/tmp/artifacts/ebuild-logs.tar.gz'])
Evan Hernandeza478d802019-04-08 15:08:24 -0600161 self.assertEqual(
162 build_ebuild_logs_tarball.call_args_list,
163 [mock.call('/cros/chroot/build', 'target', '/tmp/artifacts')])
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600164
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600165 def testBundleEbuildLogsNoLogs(self):
166 """BundleEbuildLogs dies when no logs found."""
167 self.PatchObject(commands, 'BuildEbuildLogsTarball', return_value=None)
168 with self.assertRaises(cros_build_lib.DieSystemExit):
169 artifacts.BundleEbuildLogs(self.input_proto, self.output_proto)
170
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600171
172class BundleTestUpdatePayloadsTest(cros_test_lib.MockTempDirTestCase):
173 """Unittests for BundleTestUpdatePayloads."""
174
175 def setUp(self):
176 self.source_root = os.path.join(self.tempdir, 'cros')
177 osutils.SafeMakedirs(self.source_root)
178
179 self.archive_root = os.path.join(self.tempdir, 'output')
180 osutils.SafeMakedirs(self.archive_root)
181
182 self.target = 'target'
Evan Hernandez59690b72019-04-08 16:24:45 -0600183 self.image_root = os.path.join(self.source_root,
184 'src/build/images/target/latest')
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600185
186 self.input_proto = artifacts_pb2.BundleRequest()
187 self.input_proto.build_target.name = self.target
188 self.input_proto.output_dir = self.archive_root
189 self.output_proto = artifacts_pb2.BundleResponse()
190
191 self.PatchObject(constants, 'SOURCE_ROOT', new=self.source_root)
192
193 def MockGeneratePayloads(image_path, archive_dir, **kwargs):
194 assert kwargs
195 osutils.WriteFile(os.path.join(archive_dir, 'payload.bin'), image_path)
196
197 self.generate_payloads = self.PatchObject(
198 commands, 'GeneratePayloads', side_effect=MockGeneratePayloads)
199
200 def MockGenerateQuickProvisionPayloads(image_path, archive_dir):
201 osutils.WriteFile(os.path.join(archive_dir, 'payload-qp.bin'), image_path)
202
203 self.generate_quick_provision_payloads = self.PatchObject(
204 commands,
205 'GenerateQuickProvisionPayloads',
206 side_effect=MockGenerateQuickProvisionPayloads)
207
208 def testBundleTestUpdatePayloads(self):
209 """BundleTestUpdatePayloads calls cbuildbot/commands with correct args."""
210 image_path = os.path.join(self.image_root, constants.BASE_IMAGE_BIN)
211 osutils.WriteFile(image_path, 'image!', makedirs=True)
212
213 artifacts.BundleTestUpdatePayloads(self.input_proto, self.output_proto)
214
215 actual = [
216 os.path.relpath(artifact.path, self.archive_root)
217 for artifact in self.output_proto.artifacts
218 ]
219 expected = ['payload.bin', 'payload-qp.bin']
220 self.assertItemsEqual(actual, expected)
221
222 actual = [
223 os.path.relpath(path, self.archive_root)
224 for path in osutils.DirectoryIterator(self.archive_root)
225 ]
226 self.assertItemsEqual(actual, expected)
227
228 self.assertEqual(self.generate_payloads.call_args_list, [
229 mock.call(image_path, mock.ANY, full=True, stateful=True, delta=True),
230 ])
231
232 self.assertEqual(self.generate_quick_provision_payloads.call_args_list,
233 [mock.call(image_path, mock.ANY)])
234
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600235 def testBundleTestUpdatePayloadsNoImageDir(self):
236 """BundleTestUpdatePayloads dies if no image dir is found."""
237 # Intentionally do not write image directory.
238 with self.assertRaises(cros_build_lib.DieSystemExit):
239 artifacts.BundleTestUpdatePayloads(self.input_proto, self.output_proto)
240
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600241 def testBundleTestUpdatePayloadsNoImage(self):
242 """BundleTestUpdatePayloads dies if no usable image is found for target."""
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600243 # Intentionally do not write image, but create the directory.
244 osutils.SafeMakedirs(self.image_root)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600245 with self.assertRaises(cros_build_lib.DieSystemExit):
246 artifacts.BundleTestUpdatePayloads(self.input_proto, self.output_proto)
Alex Klein6504eca2019-04-18 15:37:56 -0600247
248
249class BundleVmFilesTest(cros_test_lib.MockTestCase):
250 """BuildVmFiles tests."""
251
252 def _GetInput(self, chroot=None, sysroot=None, test_results_dir=None,
253 output_dir=None):
254 """Helper to build out an input message instance.
255
256 Args:
257 chroot (str|None): The chroot path.
258 sysroot (str|None): The sysroot path relative to the chroot.
259 test_results_dir (str|None): The test results directory relative to the
260 sysroot.
261 output_dir (str|None): The directory where the results tarball should be
262 saved.
263 """
264 return artifacts_pb2.BundleVmFilesRequest(
265 chroot={'path': chroot}, sysroot={'path': sysroot},
266 test_results_dir=test_results_dir, output_dir=output_dir,
267 )
268
269 def _GetOutput(self):
270 """Helper to get an empty output message instance."""
271 return artifacts_pb2.BundleResponse()
272
273 def testChrootMissing(self):
274 """Test error handling for missing chroot."""
275 in_proto = self._GetInput(sysroot='/build/board',
276 test_results_dir='/test/results',
277 output_dir='/tmp/output')
278 out_proto = self._GetOutput()
279
280 with self.assertRaises(cros_build_lib.DieSystemExit):
281 artifacts.BundleVmFiles(in_proto, out_proto)
282
283 def testSysrootMissing(self):
284 """Test error handling for missing sysroot."""
285 in_proto = self._GetInput(chroot='/chroot/dir',
286 test_results_dir='/test/results',
287 output_dir='/tmp/output')
288 out_proto = self._GetOutput()
289
290 with self.assertRaises(cros_build_lib.DieSystemExit):
291 artifacts.BundleVmFiles(in_proto, out_proto)
292
293
294 def testTestResultsDirMissing(self):
295 """Test error handling for missing test results directory."""
296 in_proto = self._GetInput(chroot='/chroot/dir', sysroot='/build/board',
297 output_dir='/tmp/output')
298 out_proto = self._GetOutput()
299
300 with self.assertRaises(cros_build_lib.DieSystemExit):
301 artifacts.BundleVmFiles(in_proto, out_proto)
302
303 def testOutputDirMissing(self):
304 """Test error handling for missing output directory."""
305 in_proto = self._GetInput(chroot='/chroot/dir', sysroot='/build/board',
306 test_results_dir='/test/results')
307 out_proto = self._GetOutput()
308
309 with self.assertRaises(cros_build_lib.DieSystemExit):
310 artifacts.BundleVmFiles(in_proto, out_proto)
311
312 def testValidCall(self):
313 """Test image dir building."""
314 in_proto = self._GetInput(chroot='/chroot/dir', sysroot='/build/board',
315 test_results_dir='/test/results',
316 output_dir='/tmp/output')
317 out_proto = self._GetOutput()
318 expected_files = ['/tmp/output/f1.tar', '/tmp/output/f2.tar']
319 patch = self.PatchObject(vm_test_stages, 'ArchiveVMFilesFromImageDir',
320 return_value=expected_files)
321
322 artifacts.BundleVmFiles(in_proto, out_proto)
323
324 patch.assert_called_with('/chroot/dir/build/board/test/results',
325 '/tmp/output')
326
327 # Make sure we have artifacts, and that every artifact is an expected file.
328 self.assertTrue(out_proto.artifacts)
329 for artifact in out_proto.artifacts:
330 self.assertIn(artifact.path, expected_files)
331 expected_files.remove(artifact.path)
332
333 # Make sure we've seen all of the expected files.
334 self.assertFalse(expected_files)