blob: de4f19c6488bd7dd25c039096d35cec68b0292df [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):
121 """Test that a mock call does not execute logic, returns mocked value."""
122 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):
190 """Test that a mock call does not execute logic, returns mocked value."""
191 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):
245 """Test that a mock call does not execute logic, returns mocked value."""
246 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."""
259 files = {
260 artifacts_svc.ARCHIVE_CONTROL_FILES: "/tmp/artifacts/autotest-a.tar.gz",
261 artifacts_svc.ARCHIVE_PACKAGES: "/tmp/artifacts/autotest-b.tar.gz",
262 }
263 patch = self.PatchObject(
264 artifacts_svc, "BundleAutotestFiles", return_value=files
265 )
Alex Klein238d8862019-05-07 11:32:46 -0600266
Alex Klein1699fab2022-09-08 08:46:06 -0600267 artifacts.BundleAutotestFiles(
268 self.sysroot_request, self.response, self.api_config
269 )
Alex Klein238d8862019-05-07 11:32:46 -0600270
Alex Klein1699fab2022-09-08 08:46:06 -0600271 # Verify the arguments are being passed through.
272 patch.assert_called_with(mock.ANY, self.sysroot, self.output_dir)
Alex Klein238d8862019-05-07 11:32:46 -0600273
Alex Klein1699fab2022-09-08 08:46:06 -0600274 # Verify the output proto is being populated correctly.
275 self.assertTrue(self.response.artifacts)
276 paths = [artifact.path for artifact in self.response.artifacts]
277 self.assertCountEqual(list(files.values()), paths)
Alex Klein238d8862019-05-07 11:32:46 -0600278
Alex Klein1699fab2022-09-08 08:46:06 -0600279 def testInvalidOutputDir(self):
280 """Test invalid output directory argument."""
281 request = self.SysrootRequest(
282 chroot=self.chroot_path, sysroot=self.sysroot_path
283 )
Alex Klein238d8862019-05-07 11:32:46 -0600284
Alex Klein1699fab2022-09-08 08:46:06 -0600285 with self.assertRaises(cros_build_lib.DieSystemExit):
286 artifacts.BundleAutotestFiles(
287 request, self.response, self.api_config
288 )
Alex Klein238d8862019-05-07 11:32:46 -0600289
Alex Klein1699fab2022-09-08 08:46:06 -0600290 def testInvalidSysroot(self):
291 """Test no sysroot directory."""
292 request = self.SysrootRequest(
293 chroot=self.chroot_path, output_dir=self.output_dir
294 )
Alex Klein238d8862019-05-07 11:32:46 -0600295
Alex Klein1699fab2022-09-08 08:46:06 -0600296 with self.assertRaises(cros_build_lib.DieSystemExit):
297 artifacts.BundleAutotestFiles(
298 request, self.response, self.api_config
299 )
Alex Klein238d8862019-05-07 11:32:46 -0600300
Alex Klein1699fab2022-09-08 08:46:06 -0600301 def testSysrootDoesNotExist(self):
302 """Test dies when no sysroot does not exist."""
303 request = self.SysrootRequest(
304 chroot=self.chroot_path,
305 sysroot="/does/not/exist",
306 output_dir=self.output_dir,
307 )
Alex Klein238d8862019-05-07 11:32:46 -0600308
Alex Klein1699fab2022-09-08 08:46:06 -0600309 artifacts.BundleAutotestFiles(request, self.response, self.api_config)
310 self.assertFalse(self.response.artifacts)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600311
312
313class BundleTastFilesTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600314 """Unittests for BundleTastFiles."""
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600315
Alex Klein1699fab2022-09-08 08:46:06 -0600316 def testValidateOnly(self):
317 """Quick check that a validate only call does not execute any logic."""
318 patch = self.PatchObject(artifacts_svc, "BundleTastFiles")
319 artifacts.BundleTastFiles(
320 self.sysroot_request, self.response, self.validate_only_config
321 )
322 patch.assert_not_called()
Alex Klein231d2da2019-07-22 16:44:45 -0600323
Alex Klein1699fab2022-09-08 08:46:06 -0600324 def testMockCall(self):
325 """Test that a mock call does not execute logic, returns mocked value."""
326 patch = self.PatchObject(artifacts_svc, "BundleTastFiles")
327 artifacts.BundleTastFiles(
328 self.sysroot_request, self.response, self.mock_call_config
329 )
330 patch.assert_not_called()
331 self.assertEqual(len(self.response.artifacts), 1)
332 self.assertEqual(
333 self.response.artifacts[0].path,
334 os.path.join(self.output_dir, "tast_bundles.tar.gz"),
335 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700336
Alex Klein1699fab2022-09-08 08:46:06 -0600337 def testBundleTastFilesNoLogs(self):
338 """BundleTasteFiles succeeds when no tast files found."""
339 self.PatchObject(commands, "BuildTastBundleTarball", return_value=None)
340 artifacts.BundleTastFiles(
341 self.sysroot_request, self.response, self.api_config
342 )
343 self.assertFalse(self.response.artifacts)
Alex Kleinb9d810b2019-07-01 12:38:02 -0600344
Alex Klein1699fab2022-09-08 08:46:06 -0600345 def testBundleTastFiles(self):
346 """BundleTastFiles calls service correctly."""
347 chroot = chroot_lib.Chroot(self.chroot_path)
Alex Kleinb9d810b2019-07-01 12:38:02 -0600348
Alex Klein1699fab2022-09-08 08:46:06 -0600349 expected_archive = os.path.join(
350 self.output_dir, artifacts_svc.TAST_BUNDLE_NAME
351 )
352 # Patch the service being called.
353 bundle_patch = self.PatchObject(
354 artifacts_svc, "BundleTastFiles", return_value=expected_archive
355 )
Alex Kleinb9d810b2019-07-01 12:38:02 -0600356
Alex Klein1699fab2022-09-08 08:46:06 -0600357 artifacts.BundleTastFiles(
358 self.sysroot_request, self.response, self.api_config
359 )
Alex Kleinb9d810b2019-07-01 12:38:02 -0600360
Alex Klein1699fab2022-09-08 08:46:06 -0600361 # Make sure the artifact got recorded successfully.
362 self.assertTrue(self.response.artifacts)
363 self.assertEqual(expected_archive, self.response.artifacts[0].path)
364 # Make sure the service got called correctly.
365 bundle_patch.assert_called_once_with(
366 chroot, self.sysroot, self.output_dir
367 )
Alex Kleinb9d810b2019-07-01 12:38:02 -0600368
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600369
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600370class BundleFirmwareTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600371 """Unittests for BundleFirmware."""
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600372
Alex Klein1699fab2022-09-08 08:46:06 -0600373 def testValidateOnly(self):
374 """Quick check that a validate only call does not execute any logic."""
375 patch = self.PatchObject(artifacts_svc, "BundleTastFiles")
376 artifacts.BundleFirmware(
377 self.sysroot_request, self.response, self.validate_only_config
378 )
379 patch.assert_not_called()
Michael Mortensen38675192019-06-28 16:52:55 +0000380
Alex Klein1699fab2022-09-08 08:46:06 -0600381 def testMockCall(self):
382 """Test that a mock call does not execute logic, returns mocked value."""
383 patch = self.PatchObject(artifacts_svc, "BundleTastFiles")
384 artifacts.BundleFirmware(
385 self.sysroot_request, self.response, self.mock_call_config
386 )
387 patch.assert_not_called()
388 self.assertEqual(len(self.response.artifacts), 1)
389 self.assertEqual(
390 self.response.artifacts[0].path,
391 os.path.join(self.output_dir, "firmware.tar.gz"),
392 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700393
Alex Klein1699fab2022-09-08 08:46:06 -0600394 def testBundleFirmware(self):
395 """BundleFirmware calls cbuildbot/commands with correct args."""
396 self.PatchObject(
397 artifacts_svc,
398 "BuildFirmwareArchive",
399 return_value=os.path.join(self.output_dir, "firmware.tar.gz"),
400 )
Alex Klein231d2da2019-07-22 16:44:45 -0600401
Alex Klein1699fab2022-09-08 08:46:06 -0600402 artifacts.BundleFirmware(
403 self.sysroot_request, self.response, self.api_config
404 )
405 self.assertEqual(
406 [artifact.path for artifact in self.response.artifacts],
407 [os.path.join(self.output_dir, "firmware.tar.gz")],
408 )
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600409
Alex Klein1699fab2022-09-08 08:46:06 -0600410 def testBundleFirmwareNoLogs(self):
411 """BundleFirmware dies when no firmware found."""
412 self.PatchObject(commands, "BuildFirmwareArchive", return_value=None)
413 artifacts.BundleFirmware(
414 self.sysroot_request, self.response, self.api_config
415 )
416 self.assertEqual(len(self.response.artifacts), 0)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600417
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600418
Yicheng Liea1181f2020-09-22 11:51:10 -0700419class BundleFpmcuUnittestsTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600420 """Unittests for BundleFpmcuUnittests."""
Yicheng Liea1181f2020-09-22 11:51:10 -0700421
Alex Klein1699fab2022-09-08 08:46:06 -0600422 def testValidateOnly(self):
423 """Quick check that a validate only call does not execute any logic."""
424 patch = self.PatchObject(artifacts_svc, "BundleFpmcuUnittests")
425 artifacts.BundleFpmcuUnittests(
426 self.sysroot_request, self.response, self.validate_only_config
427 )
428 patch.assert_not_called()
Yicheng Liea1181f2020-09-22 11:51:10 -0700429
Alex Klein1699fab2022-09-08 08:46:06 -0600430 def testMockCall(self):
431 """Test that a mock call does not execute logic, returns mocked value."""
432 patch = self.PatchObject(artifacts_svc, "BundleFpmcuUnittests")
433 artifacts.BundleFpmcuUnittests(
434 self.sysroot_request, self.response, self.mock_call_config
435 )
436 patch.assert_not_called()
437 self.assertEqual(len(self.response.artifacts), 1)
438 self.assertEqual(
439 self.response.artifacts[0].path,
440 os.path.join(self.output_dir, "fpmcu_unittests.tar.gz"),
441 )
Yicheng Liea1181f2020-09-22 11:51:10 -0700442
Alex Klein1699fab2022-09-08 08:46:06 -0600443 def testBundleFpmcuUnittests(self):
444 """BundleFpmcuUnittests calls cbuildbot/commands with correct args."""
445 self.PatchObject(
446 artifacts_svc,
447 "BundleFpmcuUnittests",
448 return_value=os.path.join(
449 self.output_dir, "fpmcu_unittests.tar.gz"
450 ),
451 )
452 artifacts.BundleFpmcuUnittests(
453 self.sysroot_request, self.response, self.api_config
454 )
455 self.assertEqual(
456 [artifact.path for artifact in self.response.artifacts],
457 [os.path.join(self.output_dir, "fpmcu_unittests.tar.gz")],
458 )
Yicheng Liea1181f2020-09-22 11:51:10 -0700459
Alex Klein1699fab2022-09-08 08:46:06 -0600460 def testBundleFpmcuUnittestsNoLogs(self):
461 """BundleFpmcuUnittests does not die when no fpmcu unittests found."""
462 self.PatchObject(
463 artifacts_svc, "BundleFpmcuUnittests", return_value=None
464 )
465 artifacts.BundleFpmcuUnittests(
466 self.sysroot_request, self.response, self.api_config
467 )
468 self.assertFalse(self.response.artifacts)
Yicheng Liea1181f2020-09-22 11:51:10 -0700469
470
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600471class BundleEbuildLogsTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600472 """Unittests for BundleEbuildLogs."""
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600473
Alex Klein1699fab2022-09-08 08:46:06 -0600474 def testValidateOnly(self):
475 """Quick check that a validate only call does not execute any logic."""
476 patch = self.PatchObject(commands, "BuildEbuildLogsTarball")
477 artifacts.BundleEbuildLogs(
478 self.sysroot_request, self.response, self.validate_only_config
479 )
480 patch.assert_not_called()
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600481
Alex Klein1699fab2022-09-08 08:46:06 -0600482 def testMockCall(self):
483 """Test that a mock call does not execute logic, returns mocked value."""
484 patch = self.PatchObject(commands, "BuildEbuildLogsTarball")
485 artifacts.BundleEbuildLogs(
486 self.sysroot_request, self.response, self.mock_call_config
487 )
488 patch.assert_not_called()
489 self.assertEqual(len(self.response.artifacts), 1)
490 self.assertEqual(
491 self.response.artifacts[0].path,
492 os.path.join(self.output_dir, "ebuild-logs.tar.gz"),
493 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700494
Alex Klein1699fab2022-09-08 08:46:06 -0600495 def testBundleEbuildLogs(self):
496 """BundleEbuildLogs calls cbuildbot/commands with correct args."""
497 bundle_ebuild_logs_tarball = self.PatchObject(
498 artifacts_svc,
499 "BundleEBuildLogsTarball",
500 return_value="ebuild-logs.tar.gz",
501 )
502 artifacts.BundleEbuildLogs(
503 self.sysroot_request, self.response, self.api_config
504 )
505 self.assertEqual(
506 [artifact.path for artifact in self.response.artifacts],
507 [os.path.join(self.output_dir, "ebuild-logs.tar.gz")],
508 )
509 self.assertEqual(
510 bundle_ebuild_logs_tarball.call_args_list,
511 [mock.call(mock.ANY, self.sysroot, self.output_dir)],
512 )
Michael Mortensen3f382cb2019-07-29 13:21:49 -0600513
Alex Klein1699fab2022-09-08 08:46:06 -0600514 def testBundleEbuildLogsNoLogs(self):
515 """BundleEbuildLogs dies when no logs found."""
516 self.PatchObject(commands, "BuildEbuildLogsTarball", return_value=None)
517 artifacts.BundleEbuildLogs(
518 self.sysroot_request, self.response, self.api_config
519 )
Alex Klein036833d2022-06-01 13:05:01 -0600520
Alex Klein1699fab2022-09-08 08:46:06 -0600521 self.assertFalse(self.response.artifacts)
Evan Hernandez9a5d3122019-04-09 10:51:23 -0600522
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600523
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600524class BundleChromeOSConfigTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600525 """Unittests for BundleChromeOSConfig"""
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600526
Alex Klein1699fab2022-09-08 08:46:06 -0600527 def testValidateOnly(self):
528 """Quick check that a validate only call does not execute any logic."""
529 patch = self.PatchObject(artifacts_svc, "BundleChromeOSConfig")
530 artifacts.BundleChromeOSConfig(
531 self.sysroot_request, self.response, self.validate_only_config
532 )
533 patch.assert_not_called()
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600534
Alex Klein1699fab2022-09-08 08:46:06 -0600535 def testMockCall(self):
536 """Test that a mock call does not execute logic, returns mocked value."""
537 patch = self.PatchObject(artifacts_svc, "BundleChromeOSConfig")
538 artifacts.BundleChromeOSConfig(
539 self.sysroot_request, self.response, self.mock_call_config
540 )
541 patch.assert_not_called()
542 self.assertEqual(len(self.response.artifacts), 1)
543 self.assertEqual(
544 self.response.artifacts[0].path,
545 os.path.join(self.output_dir, "config.yaml"),
546 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700547
Alex Klein1699fab2022-09-08 08:46:06 -0600548 def testBundleChromeOSConfigSuccess(self):
549 """Test standard success case."""
550 bundle_chromeos_config = self.PatchObject(
551 artifacts_svc, "BundleChromeOSConfig", return_value="config.yaml"
552 )
553 artifacts.BundleChromeOSConfig(
554 self.sysroot_request, self.response, self.api_config
555 )
556 self.assertEqual(
557 [artifact.path for artifact in self.response.artifacts],
558 [os.path.join(self.output_dir, "config.yaml")],
559 )
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600560
Alex Klein1699fab2022-09-08 08:46:06 -0600561 self.assertEqual(
562 bundle_chromeos_config.call_args_list,
563 [mock.call(mock.ANY, self.sysroot, self.output_dir)],
564 )
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600565
Alex Klein1699fab2022-09-08 08:46:06 -0600566 def testBundleChromeOSConfigNoConfigFound(self):
567 """Empty results when the config payload isn't found."""
568 self.PatchObject(
569 artifacts_svc, "BundleChromeOSConfig", return_value=None
570 )
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600571
Alex Klein1699fab2022-09-08 08:46:06 -0600572 artifacts.BundleChromeOSConfig(
573 self.sysroot_request, self.response, self.api_config
574 )
575 self.assertFalse(self.response.artifacts)
Andrew Lamb67bd68f2019-08-15 09:09:15 -0600576
577
Alex Klein1699fab2022-09-08 08:46:06 -0600578class BundleTestUpdatePayloadsTest(
579 cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin
580):
581 """Unittests for BundleTestUpdatePayloads."""
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600582
Alex Klein1699fab2022-09-08 08:46:06 -0600583 def setUp(self):
584 self.source_root = os.path.join(self.tempdir, "cros")
585 osutils.SafeMakedirs(self.source_root)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600586
Alex Klein1699fab2022-09-08 08:46:06 -0600587 self.archive_root = os.path.join(self.tempdir, "output")
588 osutils.SafeMakedirs(self.archive_root)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600589
Alex Klein1699fab2022-09-08 08:46:06 -0600590 self.target = "target"
591 self.image_root = os.path.join(
592 self.source_root, "src/build/images/target/latest"
593 )
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600594
Alex Klein1699fab2022-09-08 08:46:06 -0600595 self.input_proto = artifacts_pb2.BundleRequest()
596 self.input_proto.build_target.name = self.target
597 self.input_proto.output_dir = self.archive_root
598 self.output_proto = artifacts_pb2.BundleResponse()
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600599
Alex Klein1699fab2022-09-08 08:46:06 -0600600 self.PatchObject(constants, "SOURCE_ROOT", new=self.source_root)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600601
Alex Klein1699fab2022-09-08 08:46:06 -0600602 def MockPayloads(image_path, archive_dir):
603 osutils.WriteFile(
604 os.path.join(archive_dir, "payload1.bin"), image_path
605 )
606 osutils.WriteFile(
607 os.path.join(archive_dir, "payload2.bin"), image_path
608 )
609 return [
610 os.path.join(archive_dir, "payload1.bin"),
611 os.path.join(archive_dir, "payload2.bin"),
612 ]
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600613
Alex Klein1699fab2022-09-08 08:46:06 -0600614 self.bundle_patch = self.PatchObject(
615 artifacts_svc, "BundleTestUpdatePayloads", side_effect=MockPayloads
616 )
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600617
Alex Klein1699fab2022-09-08 08:46:06 -0600618 def testValidateOnly(self):
619 """Quick check that a validate only call does not execute any logic."""
620 patch = self.PatchObject(artifacts_svc, "BundleTestUpdatePayloads")
621 artifacts.BundleTestUpdatePayloads(
622 self.input_proto, self.output_proto, self.validate_only_config
623 )
624 patch.assert_not_called()
Alex Klein231d2da2019-07-22 16:44:45 -0600625
Alex Klein1699fab2022-09-08 08:46:06 -0600626 def testMockCall(self):
627 """Test that a mock call does not execute logic, returns mocked value."""
628 patch = self.PatchObject(artifacts_svc, "BundleTestUpdatePayloads")
629 artifacts.BundleTestUpdatePayloads(
630 self.input_proto, self.output_proto, self.mock_call_config
631 )
632 patch.assert_not_called()
633 self.assertEqual(len(self.output_proto.artifacts), 3)
634 self.assertEqual(
635 self.output_proto.artifacts[0].path,
636 os.path.join(self.archive_root, "payload1.bin"),
637 )
638 self.assertEqual(
639 self.output_proto.artifacts[1].path,
640 os.path.join(self.archive_root, "payload1.json"),
641 )
642 self.assertEqual(
643 self.output_proto.artifacts[2].path,
644 os.path.join(self.archive_root, "payload1.log"),
645 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700646
Alex Klein1699fab2022-09-08 08:46:06 -0600647 def testBundleTestUpdatePayloads(self):
648 """BundleTestUpdatePayloads calls cbuildbot/commands with correct args."""
649 image_path = os.path.join(self.image_root, constants.BASE_IMAGE_BIN)
650 osutils.WriteFile(image_path, "image!", makedirs=True)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600651
Alex Klein1699fab2022-09-08 08:46:06 -0600652 artifacts.BundleTestUpdatePayloads(
653 self.input_proto, self.output_proto, self.api_config
654 )
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600655
Alex Klein1699fab2022-09-08 08:46:06 -0600656 actual = [
657 os.path.relpath(artifact.path, self.archive_root)
658 for artifact in self.output_proto.artifacts
659 ]
660 expected = ["payload1.bin", "payload2.bin"]
661 self.assertCountEqual(actual, expected)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600662
Alex Klein1699fab2022-09-08 08:46:06 -0600663 actual = [
664 os.path.relpath(path, self.archive_root)
665 for path in osutils.DirectoryIterator(self.archive_root)
666 ]
667 self.assertCountEqual(actual, expected)
Evan Hernandezf388cbf2019-04-01 11:15:23 -0600668
Alex Klein1699fab2022-09-08 08:46:06 -0600669 def testBundleTestUpdatePayloadsNoImageDir(self):
670 """BundleTestUpdatePayloads dies if no image dir is found."""
671 # Intentionally do not write image directory.
672 artifacts.BundleTestUpdatePayloads(
673 self.input_proto, self.output_proto, self.api_config
674 )
675 self.assertFalse(self.output_proto.artifacts)
Evan Hernandez9f125ac2019-04-08 17:18:47 -0600676
Alex Klein1699fab2022-09-08 08:46:06 -0600677 def testBundleTestUpdatePayloadsNoImage(self):
678 """BundleTestUpdatePayloads dies if no usable image is found for target."""
679 # Intentionally do not write image, but create the directory.
680 osutils.SafeMakedirs(self.image_root)
681 with self.assertRaises(cros_build_lib.DieSystemExit):
682 artifacts.BundleTestUpdatePayloads(
683 self.input_proto, self.output_proto, self.api_config
684 )
Alex Klein6504eca2019-04-18 15:37:56 -0600685
686
Alex Klein1699fab2022-09-08 08:46:06 -0600687class BundleSimpleChromeArtifactsTest(
688 cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin
689):
690 """BundleSimpleChromeArtifacts tests."""
Alex Klein2275d692019-04-23 16:04:12 -0600691
Alex Klein1699fab2022-09-08 08:46:06 -0600692 def setUp(self):
693 self.chroot_dir = os.path.join(self.tempdir, "chroot_dir")
694 self.sysroot_path = "/sysroot"
695 self.sysroot_dir = os.path.join(self.chroot_dir, "sysroot")
696 osutils.SafeMakedirs(self.sysroot_dir)
697 self.output_dir = os.path.join(self.tempdir, "output_dir")
698 osutils.SafeMakedirs(self.output_dir)
Alex Klein2275d692019-04-23 16:04:12 -0600699
Alex Klein1699fab2022-09-08 08:46:06 -0600700 self.does_not_exist = os.path.join(self.tempdir, "does_not_exist")
Alex Klein2275d692019-04-23 16:04:12 -0600701
Alex Klein1699fab2022-09-08 08:46:06 -0600702 self.response = artifacts_pb2.BundleResponse()
Alex Klein231d2da2019-07-22 16:44:45 -0600703
Alex Klein1699fab2022-09-08 08:46:06 -0600704 def _GetRequest(
705 self,
706 chroot: Optional[str] = None,
707 sysroot: Optional[str] = None,
708 build_target: Optional[str] = None,
709 output_dir: Optional[str] = None,
710 ) -> artifacts_pb2.BundleRequest:
711 """Helper to create a request message instance.
Alex Klein2275d692019-04-23 16:04:12 -0600712
Alex Klein1699fab2022-09-08 08:46:06 -0600713 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600714 chroot: The chroot path.
715 sysroot: The sysroot path.
716 build_target: The build target name.
717 output_dir: The output directory.
Alex Klein1699fab2022-09-08 08:46:06 -0600718 """
719 return artifacts_pb2.BundleRequest(
720 sysroot={"path": sysroot, "build_target": {"name": build_target}},
721 chroot={"path": chroot},
722 output_dir=output_dir,
723 )
Alex Klein2275d692019-04-23 16:04:12 -0600724
Alex Klein1699fab2022-09-08 08:46:06 -0600725 def testValidateOnly(self):
726 """Quick check that a validate only call does not execute any logic."""
727 patch = self.PatchObject(artifacts_svc, "BundleSimpleChromeArtifacts")
728 request = self._GetRequest(
729 chroot=self.chroot_dir,
730 sysroot=self.sysroot_path,
731 build_target="board",
732 output_dir=self.output_dir,
733 )
734 artifacts.BundleSimpleChromeArtifacts(
735 request, self.response, self.validate_only_config
736 )
737 patch.assert_not_called()
Alex Klein2275d692019-04-23 16:04:12 -0600738
Alex Klein1699fab2022-09-08 08:46:06 -0600739 def testMockCall(self):
740 """Test that a mock call does not execute logic, returns mocked value."""
741 patch = self.PatchObject(artifacts_svc, "BundleSimpleChromeArtifacts")
742 request = self._GetRequest(
743 chroot=self.chroot_dir,
744 sysroot=self.sysroot_path,
745 build_target="board",
746 output_dir=self.output_dir,
747 )
748 artifacts.BundleSimpleChromeArtifacts(
749 request, self.response, self.mock_call_config
750 )
751 patch.assert_not_called()
752 self.assertEqual(len(self.response.artifacts), 1)
753 self.assertEqual(
754 self.response.artifacts[0].path,
755 os.path.join(self.output_dir, "simple_chrome.txt"),
756 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700757
Alex Klein1699fab2022-09-08 08:46:06 -0600758 def testNoBuildTarget(self):
759 """Test no build target fails."""
760 request = self._GetRequest(
761 chroot=self.chroot_dir,
762 sysroot=self.sysroot_path,
763 output_dir=self.output_dir,
764 )
765 response = self.response
766 with self.assertRaises(cros_build_lib.DieSystemExit):
767 artifacts.BundleSimpleChromeArtifacts(
768 request, response, self.api_config
769 )
Alex Klein2275d692019-04-23 16:04:12 -0600770
Alex Klein1699fab2022-09-08 08:46:06 -0600771 def testNoSysroot(self):
772 """Test no sysroot fails."""
773 request = self._GetRequest(
774 build_target="board", output_dir=self.output_dir
775 )
776 response = self.response
777 with self.assertRaises(cros_build_lib.DieSystemExit):
778 artifacts.BundleSimpleChromeArtifacts(
779 request, response, self.api_config
780 )
Alex Klein2275d692019-04-23 16:04:12 -0600781
Alex Klein1699fab2022-09-08 08:46:06 -0600782 def testSysrootDoesNotExist(self):
783 """Test no sysroot fails."""
784 request = self._GetRequest(
785 build_target="board",
786 output_dir=self.output_dir,
787 sysroot=self.does_not_exist,
788 )
789 response = self.response
790 with self.assertRaises(cros_build_lib.DieSystemExit):
791 artifacts.BundleSimpleChromeArtifacts(
792 request, response, self.api_config
793 )
Alex Klein2275d692019-04-23 16:04:12 -0600794
Alex Klein1699fab2022-09-08 08:46:06 -0600795 def testNoOutputDir(self):
796 """Test no output dir fails."""
797 request = self._GetRequest(
798 chroot=self.chroot_dir,
799 sysroot=self.sysroot_path,
800 build_target="board",
801 )
802 response = self.response
803 with self.assertRaises(cros_build_lib.DieSystemExit):
804 artifacts.BundleSimpleChromeArtifacts(
805 request, response, self.api_config
806 )
Alex Klein2275d692019-04-23 16:04:12 -0600807
Alex Klein1699fab2022-09-08 08:46:06 -0600808 def testOutputDirDoesNotExist(self):
809 """Test no output dir fails."""
810 request = self._GetRequest(
811 chroot=self.chroot_dir,
812 sysroot=self.sysroot_path,
813 build_target="board",
814 output_dir=self.does_not_exist,
815 )
816 response = self.response
817 with self.assertRaises(cros_build_lib.DieSystemExit):
818 artifacts.BundleSimpleChromeArtifacts(
819 request, response, self.api_config
820 )
Alex Klein2275d692019-04-23 16:04:12 -0600821
Alex Klein1699fab2022-09-08 08:46:06 -0600822 def testOutputHandling(self):
823 """Test response output."""
824 files = ["file1", "file2", "file3"]
825 expected_files = [os.path.join(self.output_dir, f) for f in files]
826 self.PatchObject(
827 artifacts_svc,
828 "BundleSimpleChromeArtifacts",
829 return_value=expected_files,
830 )
831 request = self._GetRequest(
832 chroot=self.chroot_dir,
833 sysroot=self.sysroot_path,
834 build_target="board",
835 output_dir=self.output_dir,
836 )
837 response = self.response
Alex Klein2275d692019-04-23 16:04:12 -0600838
Alex Klein1699fab2022-09-08 08:46:06 -0600839 artifacts.BundleSimpleChromeArtifacts(
840 request, response, self.api_config
841 )
Alex Klein2275d692019-04-23 16:04:12 -0600842
Alex Klein1699fab2022-09-08 08:46:06 -0600843 self.assertTrue(response.artifacts)
844 self.assertCountEqual(
845 expected_files, [a.path for a in response.artifacts]
846 )
Alex Klein2275d692019-04-23 16:04:12 -0600847
848
Alex Klein1699fab2022-09-08 08:46:06 -0600849class BundleVmFilesTest(
850 cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin
851):
852 """BuildVmFiles tests."""
Alex Klein6504eca2019-04-18 15:37:56 -0600853
Alex Klein1699fab2022-09-08 08:46:06 -0600854 def setUp(self):
855 self.output_dir = os.path.join(self.tempdir, "output")
856 osutils.SafeMakedirs(self.output_dir)
Alex Klein231d2da2019-07-22 16:44:45 -0600857
Alex Klein1699fab2022-09-08 08:46:06 -0600858 self.response = artifacts_pb2.BundleResponse()
Alex Klein231d2da2019-07-22 16:44:45 -0600859
Alex Klein1699fab2022-09-08 08:46:06 -0600860 def _GetInput(
861 self,
862 chroot: Optional[str] = None,
863 sysroot: Optional[str] = None,
864 test_results_dir: Optional[str] = None,
865 output_dir: Optional[str] = None,
866 ) -> artifacts_pb2.BundleVmFilesRequest:
867 """Helper to build out an input message instance.
Alex Klein6504eca2019-04-18 15:37:56 -0600868
Alex Klein1699fab2022-09-08 08:46:06 -0600869 Args:
Alex Klein611dddd2022-10-11 17:02:01 -0600870 chroot: The chroot path.
871 sysroot: The sysroot path relative to the chroot.
872 test_results_dir: The test results directory relative to the sysroot.
873 output_dir: The directory where the results tarball should be saved.
Alex Klein1699fab2022-09-08 08:46:06 -0600874 """
875 return artifacts_pb2.BundleVmFilesRequest(
876 chroot={"path": chroot},
877 sysroot={"path": sysroot},
878 test_results_dir=test_results_dir,
879 output_dir=output_dir,
880 )
Alex Klein6504eca2019-04-18 15:37:56 -0600881
Alex Klein1699fab2022-09-08 08:46:06 -0600882 def testValidateOnly(self):
883 """Quick check that a validate only call does not execute any logic."""
884 patch = self.PatchObject(artifacts_svc, "BundleVmFiles")
885 in_proto = self._GetInput(
886 chroot="/chroot/dir",
887 sysroot="/build/board",
888 test_results_dir="/test/results",
889 output_dir=self.output_dir,
890 )
891 artifacts.BundleVmFiles(
892 in_proto, self.response, self.validate_only_config
893 )
894 patch.assert_not_called()
Alex Klein6504eca2019-04-18 15:37:56 -0600895
Alex Klein1699fab2022-09-08 08:46:06 -0600896 def testMockCall(self):
897 """Test that a mock call does not execute logic, returns mocked value."""
898 patch = self.PatchObject(artifacts_svc, "BundleVmFiles")
899 in_proto = self._GetInput(
900 chroot="/chroot/dir",
901 sysroot="/build/board",
902 test_results_dir="/test/results",
903 output_dir=self.output_dir,
904 )
905 artifacts.BundleVmFiles(in_proto, self.response, self.mock_call_config)
906 patch.assert_not_called()
907 self.assertEqual(len(self.response.artifacts), 1)
908 self.assertEqual(
909 self.response.artifacts[0].path,
910 os.path.join(self.output_dir, "f1.tar"),
911 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -0700912
Alex Klein1699fab2022-09-08 08:46:06 -0600913 def testChrootMissing(self):
914 """Test error handling for missing chroot."""
915 in_proto = self._GetInput(
916 sysroot="/build/board",
917 test_results_dir="/test/results",
918 output_dir=self.output_dir,
919 )
Alex Klein6504eca2019-04-18 15:37:56 -0600920
Alex Klein1699fab2022-09-08 08:46:06 -0600921 with self.assertRaises(cros_build_lib.DieSystemExit):
922 artifacts.BundleVmFiles(in_proto, self.response, self.api_config)
Alex Klein6504eca2019-04-18 15:37:56 -0600923
Alex Klein1699fab2022-09-08 08:46:06 -0600924 def testTestResultsDirMissing(self):
925 """Test error handling for missing test results directory."""
926 in_proto = self._GetInput(
927 chroot="/chroot/dir",
928 sysroot="/build/board",
929 output_dir=self.output_dir,
930 )
Alex Klein6504eca2019-04-18 15:37:56 -0600931
Alex Klein1699fab2022-09-08 08:46:06 -0600932 with self.assertRaises(cros_build_lib.DieSystemExit):
933 artifacts.BundleVmFiles(in_proto, self.response, self.api_config)
Alex Klein6504eca2019-04-18 15:37:56 -0600934
Alex Klein1699fab2022-09-08 08:46:06 -0600935 def testOutputDirMissing(self):
936 """Test error handling for missing output directory."""
937 in_proto = self._GetInput(
938 chroot="/chroot/dir",
939 sysroot="/build/board",
940 test_results_dir="/test/results",
941 )
Alex Klein6504eca2019-04-18 15:37:56 -0600942
Alex Klein1699fab2022-09-08 08:46:06 -0600943 with self.assertRaises(cros_build_lib.DieSystemExit):
944 artifacts.BundleVmFiles(in_proto, self.response, self.api_config)
Alex Klein231d2da2019-07-22 16:44:45 -0600945
Alex Klein1699fab2022-09-08 08:46:06 -0600946 def testOutputDirDoesNotExist(self):
947 """Test error handling for output directory that does not exist."""
948 in_proto = self._GetInput(
949 chroot="/chroot/dir",
950 sysroot="/build/board",
951 output_dir=os.path.join(self.tempdir, "dne"),
952 test_results_dir="/test/results",
953 )
Alex Klein231d2da2019-07-22 16:44:45 -0600954
Alex Klein1699fab2022-09-08 08:46:06 -0600955 with self.assertRaises(cros_build_lib.DieSystemExit):
956 artifacts.BundleVmFiles(in_proto, self.response, self.api_config)
Alex Klein6504eca2019-04-18 15:37:56 -0600957
Alex Klein1699fab2022-09-08 08:46:06 -0600958 def testValidCall(self):
959 """Test image dir building."""
960 in_proto = self._GetInput(
961 chroot="/chroot/dir",
962 sysroot="/build/board",
963 test_results_dir="/test/results",
964 output_dir=self.output_dir,
965 )
Alex Klein231d2da2019-07-22 16:44:45 -0600966
Alex Klein1699fab2022-09-08 08:46:06 -0600967 expected_files = ["/tmp/output/f1.tar", "/tmp/output/f2.tar"]
968 patch = self.PatchObject(
969 artifacts_svc, "BundleVmFiles", return_value=expected_files
970 )
Alex Klein6504eca2019-04-18 15:37:56 -0600971
Alex Klein1699fab2022-09-08 08:46:06 -0600972 artifacts.BundleVmFiles(in_proto, self.response, self.api_config)
Alex Klein6504eca2019-04-18 15:37:56 -0600973
Alex Klein1699fab2022-09-08 08:46:06 -0600974 patch.assert_called_with(mock.ANY, "/test/results", self.output_dir)
Alex Klein6504eca2019-04-18 15:37:56 -0600975
Alex Klein1699fab2022-09-08 08:46:06 -0600976 # Make sure we have artifacts, and that every artifact is an expected file.
977 self.assertTrue(self.response.artifacts)
978 for artifact in self.response.artifacts:
979 self.assertIn(artifact.path, expected_files)
980 expected_files.remove(artifact.path)
Alex Klein6504eca2019-04-18 15:37:56 -0600981
Alex Klein1699fab2022-09-08 08:46:06 -0600982 # Make sure we've seen all of the expected files.
983 self.assertFalse(expected_files)
Alex Kleinb9d810b2019-07-01 12:38:02 -0600984
Tiancong Wang50b80a92019-08-01 14:46:15 -0700985
Alex Klein036833d2022-06-01 13:05:01 -0600986class ExportCpeReportTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600987 """ExportCpeReport tests."""
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600988
Alex Klein1699fab2022-09-08 08:46:06 -0600989 def testValidateOnly(self):
990 """Quick check validate only calls don't execute."""
991 patch = self.PatchObject(artifacts_svc, "GenerateCpeReport")
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600992
Alex Klein1699fab2022-09-08 08:46:06 -0600993 artifacts.ExportCpeReport(
994 self.sysroot_request, self.response, self.validate_only_config
995 )
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600996
Alex Klein1699fab2022-09-08 08:46:06 -0600997 patch.assert_not_called()
Alex Klein0b1cbfc2019-08-14 10:09:58 -0600998
Alex Klein1699fab2022-09-08 08:46:06 -0600999 def testMockCall(self):
1000 """Test that a mock call does not execute logic, returns mocked value."""
1001 patch = self.PatchObject(artifacts_svc, "GenerateCpeReport")
Michael Mortensen2d6a2402019-11-26 13:40:40 -07001002
Alex Klein1699fab2022-09-08 08:46:06 -06001003 artifacts.ExportCpeReport(
1004 self.sysroot_request, self.response, self.mock_call_config
1005 )
Michael Mortensen2d6a2402019-11-26 13:40:40 -07001006
Alex Klein1699fab2022-09-08 08:46:06 -06001007 patch.assert_not_called()
1008 self.assertEqual(len(self.response.artifacts), 2)
1009 self.assertEqual(
1010 self.response.artifacts[0].path,
1011 os.path.join(self.output_dir, "cpe_report.txt"),
1012 )
1013 self.assertEqual(
1014 self.response.artifacts[1].path,
1015 os.path.join(self.output_dir, "cpe_warnings.txt"),
1016 )
Alex Klein0b1cbfc2019-08-14 10:09:58 -06001017
Alex Klein1699fab2022-09-08 08:46:06 -06001018 def testSuccess(self):
1019 """Test success case."""
1020 expected = artifacts_svc.CpeResult(
1021 report="/output/report.json", warnings="/output/warnings.json"
1022 )
1023 self.PatchObject(
1024 artifacts_svc, "GenerateCpeReport", return_value=expected
1025 )
Alex Klein0b1cbfc2019-08-14 10:09:58 -06001026
Alex Klein1699fab2022-09-08 08:46:06 -06001027 artifacts.ExportCpeReport(
1028 self.sysroot_request, self.response, self.api_config
1029 )
Alex Klein0b1cbfc2019-08-14 10:09:58 -06001030
Alex Klein1699fab2022-09-08 08:46:06 -06001031 for artifact in self.response.artifacts:
1032 self.assertIn(artifact.path, [expected.report, expected.warnings])
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +09001033
1034
1035class BundleGceTarballTest(BundleTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -06001036 """Unittests for BundleGceTarball."""
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +09001037
Alex Klein1699fab2022-09-08 08:46:06 -06001038 def testValidateOnly(self):
1039 """Check that a validate only call does not execute any logic."""
1040 patch = self.PatchObject(artifacts_svc, "BundleGceTarball")
1041 artifacts.BundleGceTarball(
1042 self.target_request, self.response, self.validate_only_config
1043 )
1044 patch.assert_not_called()
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +09001045
Alex Klein1699fab2022-09-08 08:46:06 -06001046 def testMockCall(self):
1047 """Test that a mock call does not execute logic, returns mocked value."""
1048 patch = self.PatchObject(artifacts_svc, "BundleGceTarball")
1049 artifacts.BundleGceTarball(
1050 self.target_request, self.response, self.mock_call_config
1051 )
1052 patch.assert_not_called()
1053 self.assertEqual(len(self.response.artifacts), 1)
1054 self.assertEqual(
1055 self.response.artifacts[0].path,
1056 os.path.join(self.output_dir, constants.TEST_IMAGE_GCE_TAR),
1057 )
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +09001058
Alex Klein1699fab2022-09-08 08:46:06 -06001059 def testBundleGceTarball(self):
1060 """BundleGceTarball calls cbuildbot/commands with correct args."""
1061 bundle_gce_tarball = self.PatchObject(
1062 artifacts_svc,
1063 "BundleGceTarball",
1064 return_value=os.path.join(
1065 self.output_dir, constants.TEST_IMAGE_GCE_TAR
1066 ),
1067 )
1068 self.PatchObject(os.path, "exists", return_value=True)
1069 artifacts.BundleGceTarball(
1070 self.target_request, self.response, self.api_config
1071 )
1072 self.assertEqual(
1073 [artifact.path for artifact in self.response.artifacts],
1074 [os.path.join(self.output_dir, constants.TEST_IMAGE_GCE_TAR)],
1075 )
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +09001076
Alex Klein1699fab2022-09-08 08:46:06 -06001077 latest = os.path.join(
1078 self.source_root, "src/build/images/target/latest"
1079 )
1080 self.assertEqual(
1081 bundle_gce_tarball.call_args_list,
1082 [mock.call(self.output_dir, latest)],
1083 )
Shao-Chuan Leea44dddc2020-10-30 17:16:55 +09001084
Alex Klein1699fab2022-09-08 08:46:06 -06001085 def testBundleGceTarballNoImageDir(self):
1086 """BundleGceTarball dies when image dir does not exist."""
1087 self.PatchObject(os.path, "exists", return_value=False)
1088 with self.assertRaises(cros_build_lib.DieSystemExit):
1089 artifacts.BundleGceTarball(
1090 self.target_request, self.response, self.api_config
1091 )
Greg Edelstondc941072021-08-11 12:32:30 -06001092
Greg Edelstondc941072021-08-11 12:32:30 -06001093
Alex Klein1699fab2022-09-08 08:46:06 -06001094class FetchMetadataTestCase(
1095 cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin
1096):
1097 """Unittests for FetchMetadata."""
Greg Edelstondc941072021-08-11 12:32:30 -06001098
Alex Klein1699fab2022-09-08 08:46:06 -06001099 sysroot_path = "/build/coral"
1100 chroot_name = "chroot"
Greg Edelstondc941072021-08-11 12:32:30 -06001101
Alex Klein1699fab2022-09-08 08:46:06 -06001102 def setUp(self):
1103 self.PatchObject(cros_build_lib, "IsInsideChroot", return_value=False)
1104 self.chroot_path = os.path.join(self.tempdir, "chroot")
1105 pathlib.Path(self.chroot_path).touch()
1106 self.expected_filepaths = [
1107 os.path.join(self.chroot_path, fp)
1108 for fp in (
1109 "build/coral/usr/local/build/autotest/autotest_metadata.pb",
1110 "build/coral/usr/share/tast/metadata/local/cros.pb",
1111 "build/coral/build/share/tast/metadata/local/crosint.pb",
1112 "usr/share/tast/metadata/remote/cros.pb",
1113 )
1114 ]
1115 self.PatchObject(cros_build_lib, "AssertOutsideChroot")
Greg Edelstondc941072021-08-11 12:32:30 -06001116
Alex Klein1699fab2022-09-08 08:46:06 -06001117 def createFetchMetadataRequest(
1118 self, use_sysroot_path=True, use_chroot=True
1119 ):
1120 """Construct a FetchMetadataRequest for use in test cases."""
1121 request = artifacts_pb2.FetchMetadataRequest()
1122 if use_sysroot_path:
1123 request.sysroot.path = self.sysroot_path
1124 if use_chroot:
1125 request.chroot.path = self.chroot_path
1126 return request
Greg Edelstondc941072021-08-11 12:32:30 -06001127
Alex Klein1699fab2022-09-08 08:46:06 -06001128 def testValidateOnly(self):
1129 """Check that a validate only call does not execute any logic."""
1130 patch = self.PatchObject(controller_util, "ParseSysroot")
1131 request = self.createFetchMetadataRequest()
1132 response = artifacts_pb2.FetchMetadataResponse()
1133 artifacts.FetchMetadata(request, response, self.validate_only_config)
1134 patch.assert_not_called()
Greg Edelstondc941072021-08-11 12:32:30 -06001135
Alex Klein1699fab2022-09-08 08:46:06 -06001136 def testMockCall(self):
1137 """Test that a mock call does not execute logic, returns mocked value."""
1138 patch = self.PatchObject(controller_util, "ParseSysroot")
1139 request = self.createFetchMetadataRequest()
1140 response = artifacts_pb2.FetchMetadataResponse()
1141 artifacts.FetchMetadata(request, response, self.mock_call_config)
1142 patch.assert_not_called()
1143 self.assertGreater(len(response.filepaths), 0)
Greg Edelstondc941072021-08-11 12:32:30 -06001144
Alex Klein1699fab2022-09-08 08:46:06 -06001145 def testNoSysrootPath(self):
1146 """Check that a request with no sysroot.path results in failure."""
1147 request = self.createFetchMetadataRequest(use_sysroot_path=False)
1148 response = artifacts_pb2.FetchMetadataResponse()
1149 with self.assertRaises(cros_build_lib.DieSystemExit):
1150 artifacts.FetchMetadata(request, response, self.api_config)
Greg Edelstondc941072021-08-11 12:32:30 -06001151
Alex Klein1699fab2022-09-08 08:46:06 -06001152 def testNoChroot(self):
1153 """Check that a request with no chroot results in failure."""
1154 request = self.createFetchMetadataRequest(use_chroot=False)
1155 response = artifacts_pb2.FetchMetadataResponse()
1156 with self.assertRaises(cros_build_lib.DieSystemExit):
1157 artifacts.FetchMetadata(request, response, self.api_config)
1158
1159 def testSuccess(self):
1160 """Check that a well-formed request yields the expected results."""
1161 request = self.createFetchMetadataRequest(use_chroot=True)
1162 response = artifacts_pb2.FetchMetadataResponse()
1163 artifacts.FetchMetadata(request, response, self.api_config)
1164 actual_filepaths = [fp.path.path for fp in response.filepaths]
1165 self.assertEqual(
1166 sorted(actual_filepaths), sorted(self.expected_filepaths)
1167 )
1168 self.assertTrue(
1169 all(
1170 fp.path.location == common_pb2.Path.OUTSIDE
1171 for fp in response.filepaths
1172 )
1173 )
Jack Neus26b94672022-10-27 17:33:21 +00001174
1175
1176class GetTest(cros_test_lib.MockTempDirTestCase, api_config.ApiConfigMixin):
1177 """Get function tests."""
1178
1179 def setUp(self):
1180 self.sysroot_path = "/build/target"
1181 self.sysroot = sysroot_lib.Sysroot(self.sysroot_path)
1182
1183 def _InputProto(self):
1184 """Helper to build an input proto instance."""
1185 return artifacts_pb2.GetRequest(
1186 sysroot=sysroot_pb2.Sysroot(path=self.sysroot_path),
1187 artifact_info=common_pb2.ArtifactsByService(
1188 sysroot=common_pb2.ArtifactsByService.Sysroot(
1189 output_artifacts=[
1190 common_pb2.ArtifactsByService.Sysroot.ArtifactInfo(
1191 artifact_types=[
1192 common_pb2.ArtifactsByService.Sysroot.ArtifactType.FUZZER_SYSROOT
1193 ]
1194 )
1195 ],
1196 ),
1197 image=common_pb2.ArtifactsByService.Image(
1198 output_artifacts=[
1199 common_pb2.ArtifactsByService.Image.ArtifactInfo(
1200 artifact_types=[
1201 common_pb2.ArtifactsByService.Image.ArtifactType.LICENSE_CREDITS
1202 ]
1203 )
1204 ],
1205 ),
1206 test=common_pb2.ArtifactsByService.Test(
1207 output_artifacts=[
1208 common_pb2.ArtifactsByService.Test.ArtifactInfo(
1209 artifact_types=[
1210 common_pb2.ArtifactsByService.Test.ArtifactType.HWQUAL
1211 ]
1212 )
1213 ],
1214 ),
1215 ),
1216 result_path=common_pb2.ResultPath(
1217 path=common_pb2.Path(path=str(self.tempdir))
1218 ),
1219 )
1220
1221 def _OutputProto(self):
1222 """Helper to build an output proto instance."""
1223 return artifacts_pb2.GetResponse()
1224
1225 def testSuccess(self):
1226 """Test Get."""
1227 image_mock = self.PatchObject(
1228 image_controller,
1229 "GetArtifacts",
1230 return_value=[
1231 {
1232 "paths": ["/foo/bar/license_credits.html"],
1233 "type": common_pb2.ArtifactsByService.Image.ArtifactType.LICENSE_CREDITS,
1234 }
1235 ],
1236 )
1237 sysroot_mock = self.PatchObject(
1238 sysroot_controller,
1239 "GetArtifacts",
1240 return_value=[
1241 {
1242 "type": common_pb2.ArtifactsByService.Sysroot.ArtifactType.FUZZER_SYSROOT,
1243 "failed": True,
1244 "failure_reason": "Bad data!",
1245 }
1246 ],
1247 )
1248 test_mock = self.PatchObject(
1249 test_controller,
1250 "GetArtifacts",
1251 return_value=[
1252 {
1253 "paths": ["/foo/bar/hwqual.tar.xz"],
1254 "type": common_pb2.ArtifactsByService.Test.ArtifactType.HWQUAL,
1255 }
1256 ],
1257 )
1258
1259 in_proto = self._InputProto()
1260 out_proto = self._OutputProto()
1261 artifacts.Get(
1262 in_proto,
1263 out_proto,
1264 self.api_config,
1265 )
1266
1267 image_mock.assert_called_once()
1268 sysroot_mock.assert_called_once()
1269 test_mock.assert_called_once()
1270
1271 expected = common_pb2.UploadedArtifactsByService(
1272 sysroot=common_pb2.UploadedArtifactsByService.Sysroot(
1273 artifacts=[
1274 common_pb2.UploadedArtifactsByService.Sysroot.ArtifactPaths(
1275 artifact_type=common_pb2.ArtifactsByService.Sysroot.ArtifactType.FUZZER_SYSROOT,
1276 failed=True,
1277 failure_reason="Bad data!",
1278 )
1279 ]
1280 ),
1281 image=common_pb2.UploadedArtifactsByService.Image(
1282 artifacts=[
1283 common_pb2.UploadedArtifactsByService.Image.ArtifactPaths(
1284 artifact_type=common_pb2.ArtifactsByService.Image.ArtifactType.LICENSE_CREDITS,
1285 paths=[
1286 common_pb2.Path(
1287 path="/foo/bar/license_credits.html",
1288 location=common_pb2.Path.OUTSIDE,
1289 )
1290 ],
1291 )
1292 ]
1293 ),
1294 test=common_pb2.UploadedArtifactsByService.Test(
1295 artifacts=[
1296 common_pb2.UploadedArtifactsByService.Test.ArtifactPaths(
1297 artifact_type=common_pb2.ArtifactsByService.Test.ArtifactType.HWQUAL,
1298 paths=[
1299 common_pb2.Path(
1300 path="/foo/bar/hwqual.tar.xz",
1301 location=common_pb2.Path.OUTSIDE,
1302 )
1303 ],
1304 )
1305 ]
1306 ),
1307 )
1308 self.assertEqual(out_proto.artifacts, expected)