blob: 15ec2c1077e9698d4cf9b5c7f9057238f4454134 [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2019 The ChromiumOS Authors
Evan Hernandezf388cbf2019-04-01 11:15:23 -06002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Unittests for Artifacts operations."""
6
Evan Hernandezf388cbf2019-04-01 11:15:23 -06007import os
Greg Edelstondc941072021-08-11 12:32:30 -06008import pathlib
Varun Somani04dccd72021-10-09 01:06:11 +00009from typing import Optional
Mike Frysinger166fea02021-02-12 05:30:33 -050010from unittest import mock
Evan Hernandezf388cbf2019-04-01 11:15:23 -060011
Alex Klein231d2da2019-07-22 16:44:45 -060012from chromite.api import api_config
Evan Hernandezf388cbf2019-04-01 11:15:23 -060013from chromite.api.controller import artifacts
Greg Edelstondc941072021-08-11 12:32:30 -060014from chromite.api.controller import controller_util
Jack Neus26b94672022-10-27 17:33:21 +000015from chromite.api.controller import image as image_controller
16from chromite.api.controller import sysroot as sysroot_controller
17from chromite.api.controller import test as test_controller
Evan Hernandezf388cbf2019-04-01 11:15:23 -060018from chromite.api.gen.chromite.api import artifacts_pb2
Jack Neus26b94672022-10-27 17:33:21 +000019from chromite.api.gen.chromite.api import sysroot_pb2
Greg Edelstondc941072021-08-11 12:32:30 -060020from chromite.api.gen.chromiumos import common_pb2
Evan Hernandezf388cbf2019-04-01 11:15:23 -060021from chromite.cbuildbot import commands
Alex Kleinb9d810b2019-07-01 12:38:02 -060022from chromite.lib import chroot_lib
Evan Hernandezf388cbf2019-04-01 11:15:23 -060023from chromite.lib import constants
24from chromite.lib import cros_build_lib
25from chromite.lib import cros_test_lib
26from chromite.lib import osutils
Alex Klein238d8862019-05-07 11:32:46 -060027from chromite.lib import sysroot_lib
Alex Klein2275d692019-04-23 16:04:12 -060028from chromite.service import artifacts as artifacts_svc
Evan Hernandezf388cbf2019-04-01 11:15:23 -060029
30
Alex Kleind91e95a2019-09-17 10:39:02 -060031class BundleRequestMixin(object):
Alex Klein1699fab2022-09-08 08:46:06 -060032 """Mixin to provide bundle request methods."""
Alex Kleind91e95a2019-09-17 10:39:02 -060033
Alex Klein1699fab2022-09-08 08:46:06 -060034 def EmptyRequest(self):
35 return artifacts_pb2.BundleRequest()
Alex Kleind91e95a2019-09-17 10:39:02 -060036
Alex Klein1699fab2022-09-08 08:46:06 -060037 def BuildTargetRequest(
38 self, build_target=None, output_dir=None, chroot=None
39 ):
40 """Get a build target format request instance."""
41 request = self.EmptyRequest()
42 if build_target:
43 request.build_target.name = build_target
44 if output_dir:
45 request.output_dir = output_dir
46 if chroot:
47 request.chroot.path = chroot
Alex Kleind91e95a2019-09-17 10:39:02 -060048
Alex Klein1699fab2022-09-08 08:46:06 -060049 return request
Alex Kleind91e95a2019-09-17 10:39:02 -060050
Alex Klein1699fab2022-09-08 08:46:06 -060051 def SysrootRequest(
52 self, sysroot=None, build_target=None, output_dir=None, chroot=None
53 ):
54 """Get a sysroot format request instance."""
55 request = self.EmptyRequest()
56 if sysroot:
57 request.sysroot.path = sysroot
58 if build_target:
59 request.sysroot.build_target.name = build_target
60 if output_dir:
61 request.output_dir = output_dir
62 if chroot:
63 request.chroot.path = chroot
Alex Kleind91e95a2019-09-17 10:39:02 -060064
Alex Klein1699fab2022-09-08 08:46:06 -060065 return request
Alex Kleind91e95a2019-09-17 10:39:02 -060066
67
Alex Klein1699fab2022-09-08 08:46:06 -060068class BundleTestCase(
69 cros_test_lib.MockTempDirTestCase,
70 api_config.ApiConfigMixin,
71 BundleRequestMixin,
72):
73 """Basic setup for all artifacts unittests."""
Evan Hernandezf388cbf2019-04-01 11:15:23 -060074
Alex Klein1699fab2022-09-08 08:46:06 -060075 def setUp(self):
76 self.PatchObject(cros_build_lib, "IsInsideChroot", return_value=False)
77 self.output_dir = os.path.join(self.tempdir, "artifacts")
78 osutils.SafeMakedirs(self.output_dir)
79 self.sysroot_path = "/build/target"
80 self.sysroot = sysroot_lib.Sysroot(self.sysroot_path)
81 self.chroot_path = os.path.join(self.tempdir, "chroot")
82 full_sysroot_path = os.path.join(
83 self.chroot_path, self.sysroot_path.lstrip(os.sep)
84 )
85 osutils.SafeMakedirs(full_sysroot_path)
Alex Klein231d2da2019-07-22 16:44:45 -060086
Alex Klein1699fab2022-09-08 08:46:06 -060087 # All requests use same response type.
88 self.response = artifacts_pb2.BundleResponse()
Alex Klein231d2da2019-07-22 16:44:45 -060089
Alex Klein1699fab2022-09-08 08:46:06 -060090 # Build target request.
91 self.target_request = self.BuildTargetRequest(
92 build_target="target",
93 output_dir=self.output_dir,
94 chroot=self.chroot_path,
95 )
Alex Klein68c8fdf2019-09-25 15:09:11 -060096
Alex Klein1699fab2022-09-08 08:46:06 -060097 # Sysroot request.
98 self.sysroot_request = self.SysrootRequest(
99 sysroot=self.sysroot_path,
100 build_target="target",
101 output_dir=self.output_dir,
102 chroot=self.chroot_path,
103 )
Alex Klein68c8fdf2019-09-25 15:09:11 -0600104
Alex Klein1699fab2022-09-08 08:46:06 -0600105 self.source_root = self.tempdir
106 self.PatchObject(constants, "SOURCE_ROOT", new=self.tempdir)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600107
108
Alex Kleind91e95a2019-09-17 10:39:02 -0600109class BundleImageArchivesTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600110 """BundleImageArchives tests."""
Alex Kleind91e95a2019-09-17 10:39:02 -0600111
Alex Klein1699fab2022-09-08 08:46:06 -0600112 def testValidateOnly(self):
113 """Quick check that a validate only call does not execute any logic."""
114 patch = self.PatchObject(artifacts_svc, "ArchiveImages")
115 artifacts.BundleImageArchives(
116 self.target_request, self.response, self.validate_only_config
117 )
118 patch.assert_not_called()
Alex Kleind91e95a2019-09-17 10:39:02 -0600119
Alex Klein1699fab2022-09-08 08:46:06 -0600120 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700121 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -0600122 patch = self.PatchObject(artifacts_svc, "ArchiveImages")
123 artifacts.BundleImageArchives(
124 self.target_request, self.response, self.mock_call_config
125 )
126 patch.assert_not_called()
127 self.assertEqual(len(self.response.artifacts), 2)
128 self.assertEqual(
129 self.response.artifacts[0].path,
130 os.path.join(self.output_dir, "path0.tar.xz"),
131 )
132 self.assertEqual(
133 self.response.artifacts[1].path,
134 os.path.join(self.output_dir, "path1.tar.xz"),
135 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700136
Alex Klein1699fab2022-09-08 08:46:06 -0600137 def testNoBuildTarget(self):
138 """Test that no build target fails."""
139 request = self.BuildTargetRequest(output_dir=str(self.tempdir))
140 with self.assertRaises(cros_build_lib.DieSystemExit):
141 artifacts.BundleImageArchives(
142 request, self.response, self.api_config
143 )
Alex Kleind91e95a2019-09-17 10:39:02 -0600144
Alex Klein1699fab2022-09-08 08:46:06 -0600145 def testNoOutputDir(self):
146 """Test no output dir fails."""
147 request = self.BuildTargetRequest(build_target="board")
148 with self.assertRaises(cros_build_lib.DieSystemExit):
149 artifacts.BundleImageArchives(
150 request, self.response, self.api_config
151 )
Alex Kleind91e95a2019-09-17 10:39:02 -0600152
Alex Klein1699fab2022-09-08 08:46:06 -0600153 def testInvalidOutputDir(self):
154 """Test invalid output dir fails."""
155 request = self.BuildTargetRequest(
156 build_target="board", output_dir=os.path.join(self.tempdir, "DNE")
157 )
158 with self.assertRaises(cros_build_lib.DieSystemExit):
159 artifacts.BundleImageArchives(
160 request, self.response, self.api_config
161 )
Alex Kleind91e95a2019-09-17 10:39:02 -0600162
Alex Klein1699fab2022-09-08 08:46:06 -0600163 def testOutputHandling(self):
164 """Test the artifact output handling."""
165 expected = [os.path.join(self.output_dir, f) for f in ("a", "b", "c")]
166 self.PatchObject(artifacts_svc, "ArchiveImages", return_value=expected)
167 self.PatchObject(os.path, "exists", return_value=True)
Alex Kleind91e95a2019-09-17 10:39:02 -0600168
Alex Klein1699fab2022-09-08 08:46:06 -0600169 artifacts.BundleImageArchives(
170 self.target_request, self.response, self.api_config
171 )
Alex Kleind91e95a2019-09-17 10:39:02 -0600172
Alex Klein1699fab2022-09-08 08:46:06 -0600173 self.assertCountEqual(
174 expected, [a.path for a in self.response.artifacts]
175 )
Alex Kleind91e95a2019-09-17 10:39:02 -0600176
177
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600178class BundleImageZipTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600179 """Unittests for BundleImageZip."""
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600180
Alex Klein1699fab2022-09-08 08:46:06 -0600181 def testValidateOnly(self):
182 """Quick check that a validate only call does not execute any logic."""
183 patch = self.PatchObject(commands, "BuildImageZip")
184 artifacts.BundleImageZip(
185 self.target_request, self.response, self.validate_only_config
186 )
187 patch.assert_not_called()
Alex Klein231d2da2019-07-22 16:44:45 -0600188
Alex Klein1699fab2022-09-08 08:46:06 -0600189 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700190 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -0600191 patch = self.PatchObject(commands, "BuildImageZip")
192 artifacts.BundleImageZip(
193 self.target_request, self.response, self.mock_call_config
194 )
195 patch.assert_not_called()
196 self.assertEqual(len(self.response.artifacts), 1)
197 self.assertEqual(
198 self.response.artifacts[0].path,
199 os.path.join(self.output_dir, "image.zip"),
200 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700201
Alex Klein1699fab2022-09-08 08:46:06 -0600202 def testBundleImageZip(self):
203 """BundleImageZip calls cbuildbot/commands with correct args."""
204 bundle_image_zip = self.PatchObject(
205 artifacts_svc, "BundleImageZip", return_value="image.zip"
206 )
207 self.PatchObject(os.path, "exists", return_value=True)
208 artifacts.BundleImageZip(
209 self.target_request, self.response, self.api_config
210 )
211 self.assertEqual(
212 [artifact.path for artifact in self.response.artifacts],
213 [os.path.join(self.output_dir, "image.zip")],
214 )
Alex Klein231d2da2019-07-22 16:44:45 -0600215
Alex Klein1699fab2022-09-08 08:46:06 -0600216 latest = os.path.join(
217 self.source_root, "src/build/images/target/latest"
218 )
219 self.assertEqual(
220 bundle_image_zip.call_args_list,
221 [mock.call(self.output_dir, latest)],
222 )
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600223
Alex Klein1699fab2022-09-08 08:46:06 -0600224 def testBundleImageZipNoImageDir(self):
225 """BundleImageZip dies when image dir does not exist."""
226 self.PatchObject(os.path, "exists", return_value=False)
227 with self.assertRaises(cros_build_lib.DieSystemExit):
228 artifacts.BundleImageZip(
229 self.target_request, self.response, self.api_config
230 )
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600231
232
Alex Klein68c8fdf2019-09-25 15:09:11 -0600233class BundleAutotestFilesTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600234 """Unittests for BundleAutotestFiles."""
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600235
Alex Klein1699fab2022-09-08 08:46:06 -0600236 def testValidateOnly(self):
237 """Quick check that a validate only call does not execute any logic."""
238 patch = self.PatchObject(artifacts_svc, "BundleAutotestFiles")
239 artifacts.BundleAutotestFiles(
240 self.sysroot_request, self.response, self.validate_only_config
241 )
242 patch.assert_not_called()
Alex Klein231d2da2019-07-22 16:44:45 -0600243
Alex Klein1699fab2022-09-08 08:46:06 -0600244 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700245 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -0600246 patch = self.PatchObject(artifacts_svc, "BundleAutotestFiles")
247 artifacts.BundleAutotestFiles(
248 self.sysroot_request, self.response, self.mock_call_config
249 )
250 patch.assert_not_called()
251 self.assertEqual(len(self.response.artifacts), 1)
252 self.assertEqual(
253 self.response.artifacts[0].path,
254 os.path.join(self.output_dir, "autotest-a.tar.gz"),
255 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700256
Alex Klein1699fab2022-09-08 08:46:06 -0600257 def testBundleAutotestFiles(self):
258 """BundleAutotestFiles calls service correctly."""
Alex Kleinab87ceb2023-01-24 12:00:51 -0700259
Alex Klein1699fab2022-09-08 08:46:06 -0600260 files = {
Alex Kleinab87ceb2023-01-24 12:00:51 -0700261 artifacts_svc.ARCHIVE_CONTROL_FILES: (
262 "/tmp/artifacts/autotest-a.tar.gz"
263 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600264 artifacts_svc.ARCHIVE_PACKAGES: "/tmp/artifacts/autotest-b.tar.gz",
265 }
266 patch = self.PatchObject(
267 artifacts_svc, "BundleAutotestFiles", return_value=files
268 )
Alex Klein238d8862019-05-07 11:32:46 -0600269
Alex Klein1699fab2022-09-08 08:46:06 -0600270 artifacts.BundleAutotestFiles(
271 self.sysroot_request, self.response, self.api_config
272 )
Alex Klein238d8862019-05-07 11:32:46 -0600273
Alex Klein1699fab2022-09-08 08:46:06 -0600274 # Verify the arguments are being passed through.
275 patch.assert_called_with(mock.ANY, self.sysroot, self.output_dir)
Alex Klein238d8862019-05-07 11:32:46 -0600276
Alex Klein1699fab2022-09-08 08:46:06 -0600277 # Verify the output proto is being populated correctly.
278 self.assertTrue(self.response.artifacts)
279 paths = [artifact.path for artifact in self.response.artifacts]
280 self.assertCountEqual(list(files.values()), paths)
Alex Klein238d8862019-05-07 11:32:46 -0600281
Alex Klein1699fab2022-09-08 08:46:06 -0600282 def testInvalidOutputDir(self):
283 """Test invalid output directory argument."""
284 request = self.SysrootRequest(
285 chroot=self.chroot_path, sysroot=self.sysroot_path
286 )
Alex Klein238d8862019-05-07 11:32:46 -0600287
Alex Klein1699fab2022-09-08 08:46:06 -0600288 with self.assertRaises(cros_build_lib.DieSystemExit):
289 artifacts.BundleAutotestFiles(
290 request, self.response, self.api_config
291 )
Alex Klein238d8862019-05-07 11:32:46 -0600292
Alex Klein1699fab2022-09-08 08:46:06 -0600293 def testInvalidSysroot(self):
294 """Test no sysroot directory."""
295 request = self.SysrootRequest(
296 chroot=self.chroot_path, output_dir=self.output_dir
297 )
Alex Klein238d8862019-05-07 11:32:46 -0600298
Alex Klein1699fab2022-09-08 08:46:06 -0600299 with self.assertRaises(cros_build_lib.DieSystemExit):
300 artifacts.BundleAutotestFiles(
301 request, self.response, self.api_config
302 )
Alex Klein238d8862019-05-07 11:32:46 -0600303
Alex Klein1699fab2022-09-08 08:46:06 -0600304 def testSysrootDoesNotExist(self):
305 """Test dies when no sysroot does not exist."""
306 request = self.SysrootRequest(
307 chroot=self.chroot_path,
308 sysroot="/does/not/exist",
309 output_dir=self.output_dir,
310 )
Alex Klein238d8862019-05-07 11:32:46 -0600311
Alex Klein1699fab2022-09-08 08:46:06 -0600312 artifacts.BundleAutotestFiles(request, self.response, self.api_config)
313 self.assertFalse(self.response.artifacts)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600314
315
316class BundleTastFilesTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600317 """Unittests for BundleTastFiles."""
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600318
Alex Klein1699fab2022-09-08 08:46:06 -0600319 def testValidateOnly(self):
320 """Quick check that a validate only call does not execute any logic."""
321 patch = self.PatchObject(artifacts_svc, "BundleTastFiles")
322 artifacts.BundleTastFiles(
323 self.sysroot_request, self.response, self.validate_only_config
324 )
325 patch.assert_not_called()
Alex Klein231d2da2019-07-22 16:44:45 -0600326
Alex Klein1699fab2022-09-08 08:46:06 -0600327 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700328 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -0600329 patch = self.PatchObject(artifacts_svc, "BundleTastFiles")
330 artifacts.BundleTastFiles(
331 self.sysroot_request, self.response, self.mock_call_config
332 )
333 patch.assert_not_called()
334 self.assertEqual(len(self.response.artifacts), 1)
335 self.assertEqual(
336 self.response.artifacts[0].path,
337 os.path.join(self.output_dir, "tast_bundles.tar.gz"),
338 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700339
Alex Klein1699fab2022-09-08 08:46:06 -0600340 def testBundleTastFilesNoLogs(self):
341 """BundleTasteFiles succeeds when no tast files found."""
342 self.PatchObject(commands, "BuildTastBundleTarball", return_value=None)
343 artifacts.BundleTastFiles(
344 self.sysroot_request, self.response, self.api_config
345 )
346 self.assertFalse(self.response.artifacts)
Alex Kleinb9d810b2019-07-01 12:38:02 -0600347
Alex Klein1699fab2022-09-08 08:46:06 -0600348 def testBundleTastFiles(self):
349 """BundleTastFiles calls service correctly."""
350 chroot = chroot_lib.Chroot(self.chroot_path)
Alex Kleinb9d810b2019-07-01 12:38:02 -0600351
Alex Klein1699fab2022-09-08 08:46:06 -0600352 expected_archive = os.path.join(
353 self.output_dir, artifacts_svc.TAST_BUNDLE_NAME
354 )
355 # Patch the service being called.
356 bundle_patch = self.PatchObject(
357 artifacts_svc, "BundleTastFiles", return_value=expected_archive
358 )
Alex Kleinb9d810b2019-07-01 12:38:02 -0600359
Alex Klein1699fab2022-09-08 08:46:06 -0600360 artifacts.BundleTastFiles(
361 self.sysroot_request, self.response, self.api_config
362 )
Alex Kleinb9d810b2019-07-01 12:38:02 -0600363
Alex Klein1699fab2022-09-08 08:46:06 -0600364 # Make sure the artifact got recorded successfully.
365 self.assertTrue(self.response.artifacts)
366 self.assertEqual(expected_archive, self.response.artifacts[0].path)
367 # Make sure the service got called correctly.
368 bundle_patch.assert_called_once_with(
369 chroot, self.sysroot, self.output_dir
370 )
Alex Kleinb9d810b2019-07-01 12:38:02 -0600371
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600372
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600373class BundleFirmwareTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600374 """Unittests for BundleFirmware."""
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600375
Alex Klein1699fab2022-09-08 08:46:06 -0600376 def testValidateOnly(self):
377 """Quick check that a validate only call does not execute any logic."""
378 patch = self.PatchObject(artifacts_svc, "BundleTastFiles")
379 artifacts.BundleFirmware(
380 self.sysroot_request, self.response, self.validate_only_config
381 )
382 patch.assert_not_called()
Michael Mortensen38675192019-06-28 16:52:55 +0000383
Alex Klein1699fab2022-09-08 08:46:06 -0600384 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700385 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -0600386 patch = self.PatchObject(artifacts_svc, "BundleTastFiles")
387 artifacts.BundleFirmware(
388 self.sysroot_request, self.response, self.mock_call_config
389 )
390 patch.assert_not_called()
391 self.assertEqual(len(self.response.artifacts), 1)
392 self.assertEqual(
393 self.response.artifacts[0].path,
394 os.path.join(self.output_dir, "firmware.tar.gz"),
395 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700396
Alex Klein1699fab2022-09-08 08:46:06 -0600397 def testBundleFirmware(self):
398 """BundleFirmware calls cbuildbot/commands with correct args."""
399 self.PatchObject(
400 artifacts_svc,
401 "BuildFirmwareArchive",
402 return_value=os.path.join(self.output_dir, "firmware.tar.gz"),
403 )
Alex Klein231d2da2019-07-22 16:44:45 -0600404
Alex Klein1699fab2022-09-08 08:46:06 -0600405 artifacts.BundleFirmware(
406 self.sysroot_request, self.response, self.api_config
407 )
408 self.assertEqual(
409 [artifact.path for artifact in self.response.artifacts],
410 [os.path.join(self.output_dir, "firmware.tar.gz")],
411 )
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600412
Alex Klein1699fab2022-09-08 08:46:06 -0600413 def testBundleFirmwareNoLogs(self):
414 """BundleFirmware dies when no firmware found."""
415 self.PatchObject(commands, "BuildFirmwareArchive", return_value=None)
416 artifacts.BundleFirmware(
417 self.sysroot_request, self.response, self.api_config
418 )
419 self.assertEqual(len(self.response.artifacts), 0)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600420
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600421
Yicheng Liea1181f2020-09-22 11:51:10 -0700422class BundleFpmcuUnittestsTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600423 """Unittests for BundleFpmcuUnittests."""
Yicheng Liea1181f2020-09-22 11:51:10 -0700424
Alex Klein1699fab2022-09-08 08:46:06 -0600425 def testValidateOnly(self):
426 """Quick check that a validate only call does not execute any logic."""
427 patch = self.PatchObject(artifacts_svc, "BundleFpmcuUnittests")
428 artifacts.BundleFpmcuUnittests(
429 self.sysroot_request, self.response, self.validate_only_config
430 )
431 patch.assert_not_called()
Yicheng Liea1181f2020-09-22 11:51:10 -0700432
Alex Klein1699fab2022-09-08 08:46:06 -0600433 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700434 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -0600435 patch = self.PatchObject(artifacts_svc, "BundleFpmcuUnittests")
436 artifacts.BundleFpmcuUnittests(
437 self.sysroot_request, self.response, self.mock_call_config
438 )
439 patch.assert_not_called()
440 self.assertEqual(len(self.response.artifacts), 1)
441 self.assertEqual(
442 self.response.artifacts[0].path,
443 os.path.join(self.output_dir, "fpmcu_unittests.tar.gz"),
444 )
Yicheng Liea1181f2020-09-22 11:51:10 -0700445
Alex Klein1699fab2022-09-08 08:46:06 -0600446 def testBundleFpmcuUnittests(self):
447 """BundleFpmcuUnittests calls cbuildbot/commands with correct args."""
448 self.PatchObject(
449 artifacts_svc,
450 "BundleFpmcuUnittests",
451 return_value=os.path.join(
452 self.output_dir, "fpmcu_unittests.tar.gz"
453 ),
454 )
455 artifacts.BundleFpmcuUnittests(
456 self.sysroot_request, self.response, self.api_config
457 )
458 self.assertEqual(
459 [artifact.path for artifact in self.response.artifacts],
460 [os.path.join(self.output_dir, "fpmcu_unittests.tar.gz")],
461 )
Yicheng Liea1181f2020-09-22 11:51:10 -0700462
Alex Klein1699fab2022-09-08 08:46:06 -0600463 def testBundleFpmcuUnittestsNoLogs(self):
464 """BundleFpmcuUnittests does not die when no fpmcu unittests found."""
465 self.PatchObject(
466 artifacts_svc, "BundleFpmcuUnittests", return_value=None
467 )
468 artifacts.BundleFpmcuUnittests(
469 self.sysroot_request, self.response, self.api_config
470 )
471 self.assertFalse(self.response.artifacts)
Yicheng Liea1181f2020-09-22 11:51:10 -0700472
473
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600474class BundleEbuildLogsTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600475 """Unittests for BundleEbuildLogs."""
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600476
Alex Klein1699fab2022-09-08 08:46:06 -0600477 def testValidateOnly(self):
478 """Quick check that a validate only call does not execute any logic."""
479 patch = self.PatchObject(commands, "BuildEbuildLogsTarball")
480 artifacts.BundleEbuildLogs(
481 self.sysroot_request, self.response, self.validate_only_config
482 )
483 patch.assert_not_called()
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600484
Alex Klein1699fab2022-09-08 08:46:06 -0600485 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700486 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -0600487 patch = self.PatchObject(commands, "BuildEbuildLogsTarball")
488 artifacts.BundleEbuildLogs(
489 self.sysroot_request, self.response, self.mock_call_config
490 )
491 patch.assert_not_called()
492 self.assertEqual(len(self.response.artifacts), 1)
493 self.assertEqual(
494 self.response.artifacts[0].path,
495 os.path.join(self.output_dir, "ebuild-logs.tar.gz"),
496 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700497
Alex Klein1699fab2022-09-08 08:46:06 -0600498 def testBundleEbuildLogs(self):
499 """BundleEbuildLogs calls cbuildbot/commands with correct args."""
500 bundle_ebuild_logs_tarball = self.PatchObject(
501 artifacts_svc,
502 "BundleEBuildLogsTarball",
503 return_value="ebuild-logs.tar.gz",
504 )
505 artifacts.BundleEbuildLogs(
506 self.sysroot_request, self.response, self.api_config
507 )
508 self.assertEqual(
509 [artifact.path for artifact in self.response.artifacts],
510 [os.path.join(self.output_dir, "ebuild-logs.tar.gz")],
511 )
512 self.assertEqual(
513 bundle_ebuild_logs_tarball.call_args_list,
514 [mock.call(mock.ANY, self.sysroot, self.output_dir)],
515 )
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600516
Alex Klein1699fab2022-09-08 08:46:06 -0600517 def testBundleEbuildLogsNoLogs(self):
518 """BundleEbuildLogs dies when no logs found."""
519 self.PatchObject(commands, "BuildEbuildLogsTarball", return_value=None)
520 artifacts.BundleEbuildLogs(
521 self.sysroot_request, self.response, self.api_config
522 )
Alex Klein036833d2022-06-01 13:05:01 -0600523
Alex Klein1699fab2022-09-08 08:46:06 -0600524 self.assertFalse(self.response.artifacts)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600525
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600526
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600527class BundleChromeOSConfigTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600528 """Unittests for BundleChromeOSConfig"""
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600529
Alex Klein1699fab2022-09-08 08:46:06 -0600530 def testValidateOnly(self):
531 """Quick check that a validate only call does not execute any logic."""
532 patch = self.PatchObject(artifacts_svc, "BundleChromeOSConfig")
533 artifacts.BundleChromeOSConfig(
534 self.sysroot_request, self.response, self.validate_only_config
535 )
536 patch.assert_not_called()
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600537
Alex Klein1699fab2022-09-08 08:46:06 -0600538 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700539 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -0600540 patch = self.PatchObject(artifacts_svc, "BundleChromeOSConfig")
541 artifacts.BundleChromeOSConfig(
542 self.sysroot_request, self.response, self.mock_call_config
543 )
544 patch.assert_not_called()
545 self.assertEqual(len(self.response.artifacts), 1)
546 self.assertEqual(
547 self.response.artifacts[0].path,
548 os.path.join(self.output_dir, "config.yaml"),
549 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700550
Alex Klein1699fab2022-09-08 08:46:06 -0600551 def testBundleChromeOSConfigSuccess(self):
552 """Test standard success case."""
553 bundle_chromeos_config = self.PatchObject(
554 artifacts_svc, "BundleChromeOSConfig", return_value="config.yaml"
555 )
556 artifacts.BundleChromeOSConfig(
557 self.sysroot_request, self.response, self.api_config
558 )
559 self.assertEqual(
560 [artifact.path for artifact in self.response.artifacts],
561 [os.path.join(self.output_dir, "config.yaml")],
562 )
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600563
Alex Klein1699fab2022-09-08 08:46:06 -0600564 self.assertEqual(
565 bundle_chromeos_config.call_args_list,
566 [mock.call(mock.ANY, self.sysroot, self.output_dir)],
567 )
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600568
Alex Klein1699fab2022-09-08 08:46:06 -0600569 def testBundleChromeOSConfigNoConfigFound(self):
570 """Empty results when the config payload isn't found."""
571 self.PatchObject(
572 artifacts_svc, "BundleChromeOSConfig", return_value=None
573 )
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600574
Alex Klein1699fab2022-09-08 08:46:06 -0600575 artifacts.BundleChromeOSConfig(
576 self.sysroot_request, self.response, self.api_config
577 )
578 self.assertFalse(self.response.artifacts)
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600579
580
Alex Klein1699fab2022-09-08 08:46:06 -0600581class BundleTestUpdatePayloadsTest(
582 cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin
583):
584 """Unittests for BundleTestUpdatePayloads."""
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600585
Alex Klein1699fab2022-09-08 08:46:06 -0600586 def setUp(self):
587 self.source_root = os.path.join(self.tempdir, "cros")
588 osutils.SafeMakedirs(self.source_root)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600589
Alex Klein1699fab2022-09-08 08:46:06 -0600590 self.archive_root = os.path.join(self.tempdir, "output")
591 osutils.SafeMakedirs(self.archive_root)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600592
Alex Klein1699fab2022-09-08 08:46:06 -0600593 self.target = "target"
594 self.image_root = os.path.join(
595 self.source_root, "src/build/images/target/latest"
596 )
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600597
Alex Klein1699fab2022-09-08 08:46:06 -0600598 self.input_proto = artifacts_pb2.BundleRequest()
599 self.input_proto.build_target.name = self.target
600 self.input_proto.output_dir = self.archive_root
601 self.output_proto = artifacts_pb2.BundleResponse()
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600602
Alex Klein1699fab2022-09-08 08:46:06 -0600603 self.PatchObject(constants, "SOURCE_ROOT", new=self.source_root)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600604
Alex Klein1699fab2022-09-08 08:46:06 -0600605 def MockPayloads(image_path, archive_dir):
606 osutils.WriteFile(
607 os.path.join(archive_dir, "payload1.bin"), image_path
608 )
609 osutils.WriteFile(
610 os.path.join(archive_dir, "payload2.bin"), image_path
611 )
612 return [
613 os.path.join(archive_dir, "payload1.bin"),
614 os.path.join(archive_dir, "payload2.bin"),
615 ]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600616
Alex Klein1699fab2022-09-08 08:46:06 -0600617 self.bundle_patch = self.PatchObject(
618 artifacts_svc, "BundleTestUpdatePayloads", side_effect=MockPayloads
619 )
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600620
Alex Klein1699fab2022-09-08 08:46:06 -0600621 def testValidateOnly(self):
622 """Quick check that a validate only call does not execute any logic."""
623 patch = self.PatchObject(artifacts_svc, "BundleTestUpdatePayloads")
624 artifacts.BundleTestUpdatePayloads(
625 self.input_proto, self.output_proto, self.validate_only_config
626 )
627 patch.assert_not_called()
Alex Klein231d2da2019-07-22 16:44:45 -0600628
Alex Klein1699fab2022-09-08 08:46:06 -0600629 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700630 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -0600631 patch = self.PatchObject(artifacts_svc, "BundleTestUpdatePayloads")
632 artifacts.BundleTestUpdatePayloads(
633 self.input_proto, self.output_proto, self.mock_call_config
634 )
635 patch.assert_not_called()
636 self.assertEqual(len(self.output_proto.artifacts), 3)
637 self.assertEqual(
638 self.output_proto.artifacts[0].path,
639 os.path.join(self.archive_root, "payload1.bin"),
640 )
641 self.assertEqual(
642 self.output_proto.artifacts[1].path,
643 os.path.join(self.archive_root, "payload1.json"),
644 )
645 self.assertEqual(
646 self.output_proto.artifacts[2].path,
647 os.path.join(self.archive_root, "payload1.log"),
648 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700649
Alex Klein1699fab2022-09-08 08:46:06 -0600650 def testBundleTestUpdatePayloads(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700651 """BundleTestUpdatePayloads calls cbuildbot/commands correctly."""
Alex Klein1699fab2022-09-08 08:46:06 -0600652 image_path = os.path.join(self.image_root, constants.BASE_IMAGE_BIN)
653 osutils.WriteFile(image_path, "image!", makedirs=True)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600654
Alex Klein1699fab2022-09-08 08:46:06 -0600655 artifacts.BundleTestUpdatePayloads(
656 self.input_proto, self.output_proto, self.api_config
657 )
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600658
Alex Klein1699fab2022-09-08 08:46:06 -0600659 actual = [
660 os.path.relpath(artifact.path, self.archive_root)
661 for artifact in self.output_proto.artifacts
662 ]
663 expected = ["payload1.bin", "payload2.bin"]
664 self.assertCountEqual(actual, expected)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600665
Alex Klein1699fab2022-09-08 08:46:06 -0600666 actual = [
667 os.path.relpath(path, self.archive_root)
668 for path in osutils.DirectoryIterator(self.archive_root)
669 ]
670 self.assertCountEqual(actual, expected)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600671
Alex Klein1699fab2022-09-08 08:46:06 -0600672 def testBundleTestUpdatePayloadsNoImageDir(self):
673 """BundleTestUpdatePayloads dies if no image dir is found."""
674 # Intentionally do not write image directory.
675 artifacts.BundleTestUpdatePayloads(
676 self.input_proto, self.output_proto, self.api_config
677 )
678 self.assertFalse(self.output_proto.artifacts)
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600679
Alex Klein1699fab2022-09-08 08:46:06 -0600680 def testBundleTestUpdatePayloadsNoImage(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700681 """BundleTestUpdatePayloads dies if no usable image found for target."""
Alex Klein1699fab2022-09-08 08:46:06 -0600682 # Intentionally do not write image, but create the directory.
683 osutils.SafeMakedirs(self.image_root)
684 with self.assertRaises(cros_build_lib.DieSystemExit):
685 artifacts.BundleTestUpdatePayloads(
686 self.input_proto, self.output_proto, self.api_config
687 )
Alex Klein6504eca2019-04-18 15:37:56 -0600688
689
Alex Klein1699fab2022-09-08 08:46:06 -0600690class BundleSimpleChromeArtifactsTest(
691 cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin
692):
693 """BundleSimpleChromeArtifacts tests."""
Alex Klein2275d692019-04-23 16:04:12 -0600694
Alex Klein1699fab2022-09-08 08:46:06 -0600695 def setUp(self):
696 self.chroot_dir = os.path.join(self.tempdir, "chroot_dir")
697 self.sysroot_path = "/sysroot"
698 self.sysroot_dir = os.path.join(self.chroot_dir, "sysroot")
699 osutils.SafeMakedirs(self.sysroot_dir)
700 self.output_dir = os.path.join(self.tempdir, "output_dir")
701 osutils.SafeMakedirs(self.output_dir)
Alex Klein2275d692019-04-23 16:04:12 -0600702
Alex Klein1699fab2022-09-08 08:46:06 -0600703 self.does_not_exist = os.path.join(self.tempdir, "does_not_exist")
Alex Klein2275d692019-04-23 16:04:12 -0600704
Alex Klein1699fab2022-09-08 08:46:06 -0600705 self.response = artifacts_pb2.BundleResponse()
Alex Klein231d2da2019-07-22 16:44:45 -0600706
Alex Klein1699fab2022-09-08 08:46:06 -0600707 def _GetRequest(
708 self,
709 chroot: Optional[str] = None,
710 sysroot: Optional[str] = None,
711 build_target: Optional[str] = None,
712 output_dir: Optional[str] = None,
713 ) -> artifacts_pb2.BundleRequest:
714 """Helper to create a request message instance.
Alex Klein2275d692019-04-23 16:04:12 -0600715
Alex Klein1699fab2022-09-08 08:46:06 -0600716 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600717 chroot: The chroot path.
718 sysroot: The sysroot path.
719 build_target: The build target name.
720 output_dir: The output directory.
Alex Klein1699fab2022-09-08 08:46:06 -0600721 """
722 return artifacts_pb2.BundleRequest(
723 sysroot={"path": sysroot, "build_target": {"name": build_target}},
724 chroot={"path": chroot},
725 output_dir=output_dir,
726 )
Alex Klein2275d692019-04-23 16:04:12 -0600727
Alex Klein1699fab2022-09-08 08:46:06 -0600728 def testValidateOnly(self):
729 """Quick check that a validate only call does not execute any logic."""
730 patch = self.PatchObject(artifacts_svc, "BundleSimpleChromeArtifacts")
731 request = self._GetRequest(
732 chroot=self.chroot_dir,
733 sysroot=self.sysroot_path,
734 build_target="board",
735 output_dir=self.output_dir,
736 )
737 artifacts.BundleSimpleChromeArtifacts(
738 request, self.response, self.validate_only_config
739 )
740 patch.assert_not_called()
Alex Klein2275d692019-04-23 16:04:12 -0600741
Alex Klein1699fab2022-09-08 08:46:06 -0600742 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700743 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -0600744 patch = self.PatchObject(artifacts_svc, "BundleSimpleChromeArtifacts")
745 request = self._GetRequest(
746 chroot=self.chroot_dir,
747 sysroot=self.sysroot_path,
748 build_target="board",
749 output_dir=self.output_dir,
750 )
751 artifacts.BundleSimpleChromeArtifacts(
752 request, self.response, self.mock_call_config
753 )
754 patch.assert_not_called()
755 self.assertEqual(len(self.response.artifacts), 1)
756 self.assertEqual(
757 self.response.artifacts[0].path,
758 os.path.join(self.output_dir, "simple_chrome.txt"),
759 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700760
Alex Klein1699fab2022-09-08 08:46:06 -0600761 def testNoBuildTarget(self):
762 """Test no build target fails."""
763 request = self._GetRequest(
764 chroot=self.chroot_dir,
765 sysroot=self.sysroot_path,
766 output_dir=self.output_dir,
767 )
768 response = self.response
769 with self.assertRaises(cros_build_lib.DieSystemExit):
770 artifacts.BundleSimpleChromeArtifacts(
771 request, response, self.api_config
772 )
Alex Klein2275d692019-04-23 16:04:12 -0600773
Alex Klein1699fab2022-09-08 08:46:06 -0600774 def testNoSysroot(self):
775 """Test no sysroot fails."""
776 request = self._GetRequest(
777 build_target="board", output_dir=self.output_dir
778 )
779 response = self.response
780 with self.assertRaises(cros_build_lib.DieSystemExit):
781 artifacts.BundleSimpleChromeArtifacts(
782 request, response, self.api_config
783 )
Alex Klein2275d692019-04-23 16:04:12 -0600784
Alex Klein1699fab2022-09-08 08:46:06 -0600785 def testSysrootDoesNotExist(self):
786 """Test no sysroot fails."""
787 request = self._GetRequest(
788 build_target="board",
789 output_dir=self.output_dir,
790 sysroot=self.does_not_exist,
791 )
792 response = self.response
Alex Kleinb6847e22022-11-07 10:44:48 -0700793 artifacts.BundleSimpleChromeArtifacts(
794 request, response, self.api_config
795 )
796 self.assertFalse(self.response.artifacts)
Alex Klein2275d692019-04-23 16:04:12 -0600797
Alex Klein1699fab2022-09-08 08:46:06 -0600798 def testNoOutputDir(self):
799 """Test no output dir fails."""
800 request = self._GetRequest(
801 chroot=self.chroot_dir,
802 sysroot=self.sysroot_path,
803 build_target="board",
804 )
805 response = self.response
806 with self.assertRaises(cros_build_lib.DieSystemExit):
807 artifacts.BundleSimpleChromeArtifacts(
808 request, response, self.api_config
809 )
Alex Klein2275d692019-04-23 16:04:12 -0600810
Alex Klein1699fab2022-09-08 08:46:06 -0600811 def testOutputDirDoesNotExist(self):
812 """Test no output dir fails."""
813 request = self._GetRequest(
814 chroot=self.chroot_dir,
815 sysroot=self.sysroot_path,
816 build_target="board",
817 output_dir=self.does_not_exist,
818 )
819 response = self.response
820 with self.assertRaises(cros_build_lib.DieSystemExit):
821 artifacts.BundleSimpleChromeArtifacts(
822 request, response, self.api_config
823 )
Alex Klein2275d692019-04-23 16:04:12 -0600824
Alex Klein1699fab2022-09-08 08:46:06 -0600825 def testOutputHandling(self):
826 """Test response output."""
827 files = ["file1", "file2", "file3"]
828 expected_files = [os.path.join(self.output_dir, f) for f in files]
829 self.PatchObject(
830 artifacts_svc,
831 "BundleSimpleChromeArtifacts",
832 return_value=expected_files,
833 )
834 request = self._GetRequest(
835 chroot=self.chroot_dir,
836 sysroot=self.sysroot_path,
837 build_target="board",
838 output_dir=self.output_dir,
839 )
840 response = self.response
Alex Klein2275d692019-04-23 16:04:12 -0600841
Alex Klein1699fab2022-09-08 08:46:06 -0600842 artifacts.BundleSimpleChromeArtifacts(
843 request, response, self.api_config
844 )
Alex Klein2275d692019-04-23 16:04:12 -0600845
Alex Klein1699fab2022-09-08 08:46:06 -0600846 self.assertTrue(response.artifacts)
847 self.assertCountEqual(
848 expected_files, [a.path for a in response.artifacts]
849 )
Alex Klein2275d692019-04-23 16:04:12 -0600850
851
Alex Klein1699fab2022-09-08 08:46:06 -0600852class BundleVmFilesTest(
853 cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin
854):
855 """BuildVmFiles tests."""
Alex Klein6504eca2019-04-18 15:37:56 -0600856
Alex Klein1699fab2022-09-08 08:46:06 -0600857 def setUp(self):
858 self.output_dir = os.path.join(self.tempdir, "output")
859 osutils.SafeMakedirs(self.output_dir)
Alex Klein231d2da2019-07-22 16:44:45 -0600860
Alex Klein1699fab2022-09-08 08:46:06 -0600861 self.response = artifacts_pb2.BundleResponse()
Alex Klein231d2da2019-07-22 16:44:45 -0600862
Alex Klein1699fab2022-09-08 08:46:06 -0600863 def _GetInput(
864 self,
865 chroot: Optional[str] = None,
866 sysroot: Optional[str] = None,
867 test_results_dir: Optional[str] = None,
868 output_dir: Optional[str] = None,
869 ) -> artifacts_pb2.BundleVmFilesRequest:
870 """Helper to build out an input message instance.
Alex Klein6504eca2019-04-18 15:37:56 -0600871
Alex Klein1699fab2022-09-08 08:46:06 -0600872 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600873 chroot: The chroot path.
874 sysroot: The sysroot path relative to the chroot.
Alex Kleinab87ceb2023-01-24 12:00:51 -0700875 test_results_dir: The test results directory relative to the
876 sysroot.
Alex Klein611dddd2022-10-11 17:02:01 -0600877 output_dir: The directory where the results tarball should be saved.
Alex Klein1699fab2022-09-08 08:46:06 -0600878 """
879 return artifacts_pb2.BundleVmFilesRequest(
880 chroot={"path": chroot},
881 sysroot={"path": sysroot},
882 test_results_dir=test_results_dir,
883 output_dir=output_dir,
884 )
Alex Klein6504eca2019-04-18 15:37:56 -0600885
Alex Klein1699fab2022-09-08 08:46:06 -0600886 def testValidateOnly(self):
887 """Quick check that a validate only call does not execute any logic."""
888 patch = self.PatchObject(artifacts_svc, "BundleVmFiles")
889 in_proto = self._GetInput(
890 chroot="/chroot/dir",
891 sysroot="/build/board",
892 test_results_dir="/test/results",
893 output_dir=self.output_dir,
894 )
895 artifacts.BundleVmFiles(
896 in_proto, self.response, self.validate_only_config
897 )
898 patch.assert_not_called()
Alex Klein6504eca2019-04-18 15:37:56 -0600899
Alex Klein1699fab2022-09-08 08:46:06 -0600900 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700901 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -0600902 patch = self.PatchObject(artifacts_svc, "BundleVmFiles")
903 in_proto = self._GetInput(
904 chroot="/chroot/dir",
905 sysroot="/build/board",
906 test_results_dir="/test/results",
907 output_dir=self.output_dir,
908 )
909 artifacts.BundleVmFiles(in_proto, self.response, self.mock_call_config)
910 patch.assert_not_called()
911 self.assertEqual(len(self.response.artifacts), 1)
912 self.assertEqual(
913 self.response.artifacts[0].path,
914 os.path.join(self.output_dir, "f1.tar"),
915 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700916
Alex Klein1699fab2022-09-08 08:46:06 -0600917 def testChrootMissing(self):
918 """Test error handling for missing chroot."""
919 in_proto = self._GetInput(
920 sysroot="/build/board",
921 test_results_dir="/test/results",
922 output_dir=self.output_dir,
923 )
Alex Klein6504eca2019-04-18 15:37:56 -0600924
Alex Klein1699fab2022-09-08 08:46:06 -0600925 with self.assertRaises(cros_build_lib.DieSystemExit):
926 artifacts.BundleVmFiles(in_proto, self.response, self.api_config)
Alex Klein6504eca2019-04-18 15:37:56 -0600927
Alex Klein1699fab2022-09-08 08:46:06 -0600928 def testTestResultsDirMissing(self):
929 """Test error handling for missing test results directory."""
930 in_proto = self._GetInput(
931 chroot="/chroot/dir",
932 sysroot="/build/board",
933 output_dir=self.output_dir,
934 )
Alex Klein6504eca2019-04-18 15:37:56 -0600935
Alex Klein1699fab2022-09-08 08:46:06 -0600936 with self.assertRaises(cros_build_lib.DieSystemExit):
937 artifacts.BundleVmFiles(in_proto, self.response, self.api_config)
Alex Klein6504eca2019-04-18 15:37:56 -0600938
Alex Klein1699fab2022-09-08 08:46:06 -0600939 def testOutputDirMissing(self):
940 """Test error handling for missing output directory."""
941 in_proto = self._GetInput(
942 chroot="/chroot/dir",
943 sysroot="/build/board",
944 test_results_dir="/test/results",
945 )
Alex Klein6504eca2019-04-18 15:37:56 -0600946
Alex Klein1699fab2022-09-08 08:46:06 -0600947 with self.assertRaises(cros_build_lib.DieSystemExit):
948 artifacts.BundleVmFiles(in_proto, self.response, self.api_config)
Alex Klein231d2da2019-07-22 16:44:45 -0600949
Alex Klein1699fab2022-09-08 08:46:06 -0600950 def testOutputDirDoesNotExist(self):
951 """Test error handling for output directory that does not exist."""
952 in_proto = self._GetInput(
953 chroot="/chroot/dir",
954 sysroot="/build/board",
955 output_dir=os.path.join(self.tempdir, "dne"),
956 test_results_dir="/test/results",
957 )
Alex Klein231d2da2019-07-22 16:44:45 -0600958
Alex Klein1699fab2022-09-08 08:46:06 -0600959 with self.assertRaises(cros_build_lib.DieSystemExit):
960 artifacts.BundleVmFiles(in_proto, self.response, self.api_config)
Alex Klein6504eca2019-04-18 15:37:56 -0600961
Alex Klein1699fab2022-09-08 08:46:06 -0600962 def testValidCall(self):
963 """Test image dir building."""
964 in_proto = self._GetInput(
965 chroot="/chroot/dir",
966 sysroot="/build/board",
967 test_results_dir="/test/results",
968 output_dir=self.output_dir,
969 )
Alex Klein231d2da2019-07-22 16:44:45 -0600970
Alex Klein1699fab2022-09-08 08:46:06 -0600971 expected_files = ["/tmp/output/f1.tar", "/tmp/output/f2.tar"]
972 patch = self.PatchObject(
973 artifacts_svc, "BundleVmFiles", return_value=expected_files
974 )
Alex Klein6504eca2019-04-18 15:37:56 -0600975
Alex Klein1699fab2022-09-08 08:46:06 -0600976 artifacts.BundleVmFiles(in_proto, self.response, self.api_config)
Alex Klein6504eca2019-04-18 15:37:56 -0600977
Alex Klein1699fab2022-09-08 08:46:06 -0600978 patch.assert_called_with(mock.ANY, "/test/results", self.output_dir)
Alex Klein6504eca2019-04-18 15:37:56 -0600979
Alex Kleinab87ceb2023-01-24 12:00:51 -0700980 # Make sure we have artifacts, and that every artifact is an expected
981 # file.
Alex Klein1699fab2022-09-08 08:46:06 -0600982 self.assertTrue(self.response.artifacts)
983 for artifact in self.response.artifacts:
984 self.assertIn(artifact.path, expected_files)
985 expected_files.remove(artifact.path)
Alex Klein6504eca2019-04-18 15:37:56 -0600986
Alex Klein1699fab2022-09-08 08:46:06 -0600987 # Make sure we've seen all of the expected files.
988 self.assertFalse(expected_files)
Alex Kleinb9d810b2019-07-01 12:38:02 -0600989
Tiancong Wang50b80a92019-08-01 14:46:15 -0700990
Alex Klein036833d2022-06-01 13:05:01 -0600991class ExportCpeReportTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600992 """ExportCpeReport tests."""
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600993
Alex Klein1699fab2022-09-08 08:46:06 -0600994 def testValidateOnly(self):
995 """Quick check validate only calls don't execute."""
996 patch = self.PatchObject(artifacts_svc, "GenerateCpeReport")
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600997
Alex Klein1699fab2022-09-08 08:46:06 -0600998 artifacts.ExportCpeReport(
999 self.sysroot_request, self.response, self.validate_only_config
1000 )
Alex Klein0b1cbfc2019-08-14 10:09:58 -06001001
Alex Klein1699fab2022-09-08 08:46:06 -06001002 patch.assert_not_called()
Alex Klein0b1cbfc2019-08-14 10:09:58 -06001003
Alex Klein1699fab2022-09-08 08:46:06 -06001004 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -07001005 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -06001006 patch = self.PatchObject(artifacts_svc, "GenerateCpeReport")
Michael Mortensen2d6a2402019-11-26 13:40:40 -07001007
Alex Klein1699fab2022-09-08 08:46:06 -06001008 artifacts.ExportCpeReport(
1009 self.sysroot_request, self.response, self.mock_call_config
1010 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -07001011
Alex Klein1699fab2022-09-08 08:46:06 -06001012 patch.assert_not_called()
1013 self.assertEqual(len(self.response.artifacts), 2)
1014 self.assertEqual(
1015 self.response.artifacts[0].path,
1016 os.path.join(self.output_dir, "cpe_report.txt"),
1017 )
1018 self.assertEqual(
1019 self.response.artifacts[1].path,
1020 os.path.join(self.output_dir, "cpe_warnings.txt"),
1021 )
Alex Klein0b1cbfc2019-08-14 10:09:58 -06001022
Alex Klein1699fab2022-09-08 08:46:06 -06001023 def testSuccess(self):
1024 """Test success case."""
1025 expected = artifacts_svc.CpeResult(
1026 report="/output/report.json", warnings="/output/warnings.json"
1027 )
1028 self.PatchObject(
1029 artifacts_svc, "GenerateCpeReport", return_value=expected
1030 )
Alex Klein0b1cbfc2019-08-14 10:09:58 -06001031
Alex Klein1699fab2022-09-08 08:46:06 -06001032 artifacts.ExportCpeReport(
1033 self.sysroot_request, self.response, self.api_config
1034 )
Alex Klein0b1cbfc2019-08-14 10:09:58 -06001035
Alex Klein1699fab2022-09-08 08:46:06 -06001036 for artifact in self.response.artifacts:
1037 self.assertIn(artifact.path, [expected.report, expected.warnings])
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +09001038
1039
1040class BundleGceTarballTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -06001041 """Unittests for BundleGceTarball."""
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +09001042
Alex Klein1699fab2022-09-08 08:46:06 -06001043 def testValidateOnly(self):
1044 """Check that a validate only call does not execute any logic."""
1045 patch = self.PatchObject(artifacts_svc, "BundleGceTarball")
1046 artifacts.BundleGceTarball(
1047 self.target_request, self.response, self.validate_only_config
1048 )
1049 patch.assert_not_called()
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +09001050
Alex Klein1699fab2022-09-08 08:46:06 -06001051 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -07001052 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -06001053 patch = self.PatchObject(artifacts_svc, "BundleGceTarball")
1054 artifacts.BundleGceTarball(
1055 self.target_request, self.response, self.mock_call_config
1056 )
1057 patch.assert_not_called()
1058 self.assertEqual(len(self.response.artifacts), 1)
1059 self.assertEqual(
1060 self.response.artifacts[0].path,
1061 os.path.join(self.output_dir, constants.TEST_IMAGE_GCE_TAR),
1062 )
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +09001063
Alex Klein1699fab2022-09-08 08:46:06 -06001064 def testBundleGceTarball(self):
1065 """BundleGceTarball calls cbuildbot/commands with correct args."""
1066 bundle_gce_tarball = self.PatchObject(
1067 artifacts_svc,
1068 "BundleGceTarball",
1069 return_value=os.path.join(
1070 self.output_dir, constants.TEST_IMAGE_GCE_TAR
1071 ),
1072 )
1073 self.PatchObject(os.path, "exists", return_value=True)
1074 artifacts.BundleGceTarball(
1075 self.target_request, self.response, self.api_config
1076 )
1077 self.assertEqual(
1078 [artifact.path for artifact in self.response.artifacts],
1079 [os.path.join(self.output_dir, constants.TEST_IMAGE_GCE_TAR)],
1080 )
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +09001081
Alex Klein1699fab2022-09-08 08:46:06 -06001082 latest = os.path.join(
1083 self.source_root, "src/build/images/target/latest"
1084 )
1085 self.assertEqual(
1086 bundle_gce_tarball.call_args_list,
1087 [mock.call(self.output_dir, latest)],
1088 )
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +09001089
Alex Klein1699fab2022-09-08 08:46:06 -06001090 def testBundleGceTarballNoImageDir(self):
1091 """BundleGceTarball dies when image dir does not exist."""
1092 self.PatchObject(os.path, "exists", return_value=False)
1093 with self.assertRaises(cros_build_lib.DieSystemExit):
1094 artifacts.BundleGceTarball(
1095 self.target_request, self.response, self.api_config
1096 )
Greg Edelstondc941072021-08-11 12:32:30 -06001097
Greg Edelstondc941072021-08-11 12:32:30 -06001098
Alex Klein1699fab2022-09-08 08:46:06 -06001099class FetchMetadataTestCase(
1100 cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin
1101):
1102 """Unittests for FetchMetadata."""
Greg Edelstondc941072021-08-11 12:32:30 -06001103
Alex Klein1699fab2022-09-08 08:46:06 -06001104 sysroot_path = "/build/coral"
1105 chroot_name = "chroot"
Greg Edelstondc941072021-08-11 12:32:30 -06001106
Alex Klein1699fab2022-09-08 08:46:06 -06001107 def setUp(self):
1108 self.PatchObject(cros_build_lib, "IsInsideChroot", return_value=False)
1109 self.chroot_path = os.path.join(self.tempdir, "chroot")
1110 pathlib.Path(self.chroot_path).touch()
1111 self.expected_filepaths = [
1112 os.path.join(self.chroot_path, fp)
1113 for fp in (
1114 "build/coral/usr/local/build/autotest/autotest_metadata.pb",
1115 "build/coral/usr/share/tast/metadata/local/cros.pb",
1116 "build/coral/build/share/tast/metadata/local/crosint.pb",
1117 "usr/share/tast/metadata/remote/cros.pb",
1118 )
1119 ]
1120 self.PatchObject(cros_build_lib, "AssertOutsideChroot")
Greg Edelstondc941072021-08-11 12:32:30 -06001121
Alex Klein1699fab2022-09-08 08:46:06 -06001122 def createFetchMetadataRequest(
1123 self, use_sysroot_path=True, use_chroot=True
1124 ):
1125 """Construct a FetchMetadataRequest for use in test cases."""
1126 request = artifacts_pb2.FetchMetadataRequest()
1127 if use_sysroot_path:
1128 request.sysroot.path = self.sysroot_path
1129 if use_chroot:
1130 request.chroot.path = self.chroot_path
1131 return request
Greg Edelstondc941072021-08-11 12:32:30 -06001132
Alex Klein1699fab2022-09-08 08:46:06 -06001133 def testValidateOnly(self):
1134 """Check that a validate only call does not execute any logic."""
1135 patch = self.PatchObject(controller_util, "ParseSysroot")
1136 request = self.createFetchMetadataRequest()
1137 response = artifacts_pb2.FetchMetadataResponse()
1138 artifacts.FetchMetadata(request, response, self.validate_only_config)
1139 patch.assert_not_called()
Greg Edelstondc941072021-08-11 12:32:30 -06001140
Alex Klein1699fab2022-09-08 08:46:06 -06001141 def testMockCall(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -07001142 """Test a mock call does not execute logic, returns mocked value."""
Alex Klein1699fab2022-09-08 08:46:06 -06001143 patch = self.PatchObject(controller_util, "ParseSysroot")
1144 request = self.createFetchMetadataRequest()
1145 response = artifacts_pb2.FetchMetadataResponse()
1146 artifacts.FetchMetadata(request, response, self.mock_call_config)
1147 patch.assert_not_called()
1148 self.assertGreater(len(response.filepaths), 0)
Greg Edelstondc941072021-08-11 12:32:30 -06001149
Alex Klein1699fab2022-09-08 08:46:06 -06001150 def testNoSysrootPath(self):
1151 """Check that a request with no sysroot.path results in failure."""
1152 request = self.createFetchMetadataRequest(use_sysroot_path=False)
1153 response = artifacts_pb2.FetchMetadataResponse()
1154 with self.assertRaises(cros_build_lib.DieSystemExit):
1155 artifacts.FetchMetadata(request, response, self.api_config)
Greg Edelstondc941072021-08-11 12:32:30 -06001156
Alex Klein1699fab2022-09-08 08:46:06 -06001157 def testNoChroot(self):
1158 """Check that a request with no chroot results in failure."""
1159 request = self.createFetchMetadataRequest(use_chroot=False)
1160 response = artifacts_pb2.FetchMetadataResponse()
1161 with self.assertRaises(cros_build_lib.DieSystemExit):
1162 artifacts.FetchMetadata(request, response, self.api_config)
1163
1164 def testSuccess(self):
1165 """Check that a well-formed request yields the expected results."""
1166 request = self.createFetchMetadataRequest(use_chroot=True)
1167 response = artifacts_pb2.FetchMetadataResponse()
1168 artifacts.FetchMetadata(request, response, self.api_config)
1169 actual_filepaths = [fp.path.path for fp in response.filepaths]
1170 self.assertEqual(
1171 sorted(actual_filepaths), sorted(self.expected_filepaths)
1172 )
1173 self.assertTrue(
1174 all(
1175 fp.path.location == common_pb2.Path.OUTSIDE
1176 for fp in response.filepaths
1177 )
1178 )
Jack Neus26b94672022-10-27 17:33:21 +00001179
1180
1181class GetTest(cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin):
1182 """Get function tests."""
1183
1184 def setUp(self):
1185 self.sysroot_path = "/build/target"
1186 self.sysroot = sysroot_lib.Sysroot(self.sysroot_path)
1187
1188 def _InputProto(self):
1189 """Helper to build an input proto instance."""
Alex Kleinab87ceb2023-01-24 12:00:51 -07001190 # pylint: disable=line-too-long
Jack Neus26b94672022-10-27 17:33:21 +00001191 return artifacts_pb2.GetRequest(
1192 sysroot=sysroot_pb2.Sysroot(path=self.sysroot_path),
1193 artifact_info=common_pb2.ArtifactsByService(
1194 sysroot=common_pb2.ArtifactsByService.Sysroot(
1195 output_artifacts=[
1196 common_pb2.ArtifactsByService.Sysroot.ArtifactInfo(
1197 artifact_types=[
1198 common_pb2.ArtifactsByService.Sysroot.ArtifactType.FUZZER_SYSROOT
1199 ]
1200 )
1201 ],
1202 ),
1203 image=common_pb2.ArtifactsByService.Image(
1204 output_artifacts=[
1205 common_pb2.ArtifactsByService.Image.ArtifactInfo(
1206 artifact_types=[
1207 common_pb2.ArtifactsByService.Image.ArtifactType.LICENSE_CREDITS
1208 ]
1209 )
1210 ],
1211 ),
1212 test=common_pb2.ArtifactsByService.Test(
1213 output_artifacts=[
1214 common_pb2.ArtifactsByService.Test.ArtifactInfo(
1215 artifact_types=[
1216 common_pb2.ArtifactsByService.Test.ArtifactType.HWQUAL
1217 ]
1218 )
1219 ],
1220 ),
1221 ),
1222 result_path=common_pb2.ResultPath(
1223 path=common_pb2.Path(path=str(self.tempdir))
1224 ),
1225 )
Alex Kleinab87ceb2023-01-24 12:00:51 -07001226 # pylint: enable=line-too-long
Jack Neus26b94672022-10-27 17:33:21 +00001227
1228 def _OutputProto(self):
1229 """Helper to build an output proto instance."""
1230 return artifacts_pb2.GetResponse()
1231
1232 def testSuccess(self):
1233 """Test Get."""
Alex Kleinab87ceb2023-01-24 12:00:51 -07001234 # pylint: disable=line-too-long
Jack Neus26b94672022-10-27 17:33:21 +00001235 image_mock = self.PatchObject(
1236 image_controller,
1237 "GetArtifacts",
1238 return_value=[
1239 {
1240 "paths": ["/foo/bar/license_credits.html"],
1241 "type": common_pb2.ArtifactsByService.Image.ArtifactType.LICENSE_CREDITS,
1242 }
1243 ],
1244 )
1245 sysroot_mock = self.PatchObject(
1246 sysroot_controller,
1247 "GetArtifacts",
1248 return_value=[
1249 {
1250 "type": common_pb2.ArtifactsByService.Sysroot.ArtifactType.FUZZER_SYSROOT,
1251 "failed": True,
1252 "failure_reason": "Bad data!",
1253 }
1254 ],
1255 )
1256 test_mock = self.PatchObject(
1257 test_controller,
1258 "GetArtifacts",
1259 return_value=[
1260 {
1261 "paths": ["/foo/bar/hwqual.tar.xz"],
1262 "type": common_pb2.ArtifactsByService.Test.ArtifactType.HWQUAL,
1263 }
1264 ],
1265 )
Alex Kleinab87ceb2023-01-24 12:00:51 -07001266 # pylint: enable=line-too-long
Jack Neus26b94672022-10-27 17:33:21 +00001267
1268 in_proto = self._InputProto()
1269 out_proto = self._OutputProto()
1270 artifacts.Get(
1271 in_proto,
1272 out_proto,
1273 self.api_config,
1274 )
1275
1276 image_mock.assert_called_once()
1277 sysroot_mock.assert_called_once()
1278 test_mock.assert_called_once()
1279
Alex Kleinab87ceb2023-01-24 12:00:51 -07001280 # pylint: disable=line-too-long
Jack Neus26b94672022-10-27 17:33:21 +00001281 expected = common_pb2.UploadedArtifactsByService(
1282 sysroot=common_pb2.UploadedArtifactsByService.Sysroot(
1283 artifacts=[
1284 common_pb2.UploadedArtifactsByService.Sysroot.ArtifactPaths(
1285 artifact_type=common_pb2.ArtifactsByService.Sysroot.ArtifactType.FUZZER_SYSROOT,
1286 failed=True,
1287 failure_reason="Bad data!",
1288 )
1289 ]
1290 ),
1291 image=common_pb2.UploadedArtifactsByService.Image(
1292 artifacts=[
1293 common_pb2.UploadedArtifactsByService.Image.ArtifactPaths(
1294 artifact_type=common_pb2.ArtifactsByService.Image.ArtifactType.LICENSE_CREDITS,
1295 paths=[
1296 common_pb2.Path(
1297 path="/foo/bar/license_credits.html",
1298 location=common_pb2.Path.OUTSIDE,
1299 )
1300 ],
1301 )
1302 ]
1303 ),
1304 test=common_pb2.UploadedArtifactsByService.Test(
1305 artifacts=[
1306 common_pb2.UploadedArtifactsByService.Test.ArtifactPaths(
1307 artifact_type=common_pb2.ArtifactsByService.Test.ArtifactType.HWQUAL,
1308 paths=[
1309 common_pb2.Path(
1310 path="/foo/bar/hwqual.tar.xz",
1311 location=common_pb2.Path.OUTSIDE,
1312 )
1313 ],
1314 )
1315 ]
1316 ),
1317 )
Alex Kleinab87ceb2023-01-24 12:00:51 -07001318 # pylint: enable=line-too-long
Jack Neus26b94672022-10-27 17:33:21 +00001319 self.assertEqual(out_proto.artifacts, expected)