blob: 59e14e710f3130d6609f137b1f1ee24f2a0bc677 [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2012 The ChromiumOS Authors
David James8c846492011-01-25 17:07:29 -08002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Mike Frysingerc6824f62014-02-03 11:09:44 -05005"""Unittests for upload_prebuilts.py."""
6
David James8c846492011-01-25 17:07:29 -08007import copy
David James8fa34ea2011-04-15 13:00:20 -07008import multiprocessing
Mike Frysinger40ffb532021-02-12 07:36:08 -05009import os
Greg Edelston325e4412023-05-04 16:22:10 -060010from typing import List
Mike Frysinger166fea02021-02-12 05:30:33 -050011from unittest import mock
Chris Sosa471532a2011-02-01 15:10:06 -080012
Greg Edelston325e4412023-05-04 16:22:10 -060013import pytest
14
Mike Frysinger40ffb532021-02-12 07:36:08 -050015from chromite.lib import binpkg
Brian Harringc92788f2012-09-21 18:07:15 -070016from chromite.lib import cros_test_lib
David James2c7ccb42012-11-04 15:34:28 -080017from chromite.lib import gs
Zdenek Behanc0e18762012-09-22 04:06:17 +020018from chromite.lib import osutils
Mike Frysinger36870f92015-04-12 02:59:55 -040019from chromite.lib import parallel_unittest
Prathmesh Prabhu421eef22014-10-16 17:13:19 -070020from chromite.lib import portage_util
Mike Frysinger40ffb532021-02-12 07:36:08 -050021from chromite.scripts import upload_prebuilts as prebuilt
David James8c846492011-01-25 17:07:29 -080022
Mike Frysinger68182472014-11-05 22:38:39 -050023
Mike Frysinger27e21b72018-07-12 14:20:21 -040024# pylint: disable=protected-access
25
26
Alex Klein1699fab2022-09-08 08:46:06 -060027PUBLIC_PACKAGES = [
28 {"CPV": "gtk+/public1", "SHA1": "1", "MTIME": "1"},
29 {"CPV": "gtk+/public2", "SHA1": "2", "PATH": "gtk+/foo.tgz", "MTIME": "2"},
30]
31PRIVATE_PACKAGES = [{"CPV": "private", "SHA1": "3", "MTIME": "3"}]
David James8c846492011-01-25 17:07:29 -080032
33
34def SimplePackageIndex(header=True, packages=True):
Alex Klein1699fab2022-09-08 08:46:06 -060035 pkgindex = binpkg.PackageIndex()
36 if header:
37 pkgindex.header["URI"] = "gs://example"
38 if packages:
39 pkgindex.packages = copy.deepcopy(PUBLIC_PACKAGES + PRIVATE_PACKAGES)
40 return pkgindex
David James8c846492011-01-25 17:07:29 -080041
42
Mike Frysinger68182472014-11-05 22:38:39 -050043class TestPrebuilt(cros_test_lib.MockTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -060044 """Tests for Prebuilt logic."""
David James8c846492011-01-25 17:07:29 -080045
Alex Klein1699fab2022-09-08 08:46:06 -060046 def setUp(self):
47 self._base_local_path = "/b/cbuild/build/chroot/build/x86-dogfood/"
48 self._gs_bucket_path = "gs://chromeos-prebuilt/host/version"
49 self._local_path = os.path.join(self._base_local_path, "public1.tbz2")
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -080050
Alex Klein1699fab2022-09-08 08:46:06 -060051 def testGenerateUploadDict(self):
52 self.PatchObject(prebuilt.os.path, "exists", return_true=True)
53 pkgs = [{"CPV": "public1"}]
54 result = prebuilt.GenerateUploadDict(
55 self._base_local_path, self._gs_bucket_path, pkgs
56 )
57 expected = {
58 self._local_path: self._gs_bucket_path + "/public1.tbz2",
59 }
60 self.assertEqual(result, expected)
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -080061
Alex Klein1699fab2022-09-08 08:46:06 -060062 def testGenerateUploadDictWithDebug(self):
63 self.PatchObject(prebuilt.os.path, "exists", return_true=True)
64 pkgs = [{"CPV": "public1", "DEBUG_SYMBOLS": "yes"}]
65 result = prebuilt.GenerateUploadDict(
66 self._base_local_path, self._gs_bucket_path, pkgs
67 )
68 expected = {
69 self._local_path: self._gs_bucket_path + "/public1.tbz2",
Trent Aptedc20bb6d2023-05-10 15:00:03 +100070 self._local_path.replace(".tbz2", ".debug.tbz2"): (
71 self._gs_bucket_path + "/public1.debug.tbz2"
72 ),
Alex Klein1699fab2022-09-08 08:46:06 -060073 }
74 self.assertEqual(result, expected)
David James8c846492011-01-25 17:07:29 -080075
Alex Klein1699fab2022-09-08 08:46:06 -060076 def testDeterminePrebuiltConfHost(self):
77 """Test that the host prebuilt path comes back properly."""
78 expected_path = os.path.join(prebuilt._PREBUILT_MAKE_CONF["amd64"])
79 self.assertEqual(
80 prebuilt.DeterminePrebuiltConfFile("fake_path", "amd64"),
81 expected_path,
82 )
David James8c846492011-01-25 17:07:29 -080083
David James8c846492011-01-25 17:07:29 -080084
David James2c7ccb42012-11-04 15:34:28 -080085class TestPkgIndex(cros_test_lib.TestCase):
Alex Klein1699fab2022-09-08 08:46:06 -060086 """Helper for tests that update the Packages index file."""
David James2c7ccb42012-11-04 15:34:28 -080087
Alex Klein1699fab2022-09-08 08:46:06 -060088 def setUp(self):
89 self.db = {}
90 self.pkgindex = SimplePackageIndex()
91 self.empty = SimplePackageIndex(packages=False)
David James2c7ccb42012-11-04 15:34:28 -080092
Alex Klein1699fab2022-09-08 08:46:06 -060093 def assertURIs(self, uris):
94 """Verify that the duplicate DB has the specified URLs."""
95 expected = [v.uri for _, v in sorted(self.db.items())]
96 self.assertEqual(expected, uris)
David James2c7ccb42012-11-04 15:34:28 -080097
98
99class TestPackagesFileFiltering(TestPkgIndex):
Alex Klein1699fab2022-09-08 08:46:06 -0600100 """Tests for Packages filtering behavior."""
David James8c846492011-01-25 17:07:29 -0800101
Alex Klein1699fab2022-09-08 08:46:06 -0600102 def testFilterPkgIndex(self):
103 """Test filtering out of private packages."""
104 self.pkgindex.RemoveFilteredPackages(
105 lambda pkg: pkg in PRIVATE_PACKAGES
106 )
107 self.assertEqual(self.pkgindex.packages, PUBLIC_PACKAGES)
108 self.assertEqual(self.pkgindex.modified, True)
David James8c846492011-01-25 17:07:29 -0800109
110
David James2c7ccb42012-11-04 15:34:28 -0800111class TestPopulateDuplicateDB(TestPkgIndex):
Alex Klein1699fab2022-09-08 08:46:06 -0600112 """Tests for the _PopulateDuplicateDB function."""
David James8c846492011-01-25 17:07:29 -0800113
Alex Klein1699fab2022-09-08 08:46:06 -0600114 def testEmptyIndex(self):
115 """Test population of the duplicate DB with an empty index."""
116 self.empty._PopulateDuplicateDB(self.db, 0)
117 self.assertEqual(self.db, {})
David James8c846492011-01-25 17:07:29 -0800118
Alex Klein1699fab2022-09-08 08:46:06 -0600119 def testNormalIndex(self):
120 """Test population of the duplicate DB with a full index."""
121 self.pkgindex._PopulateDuplicateDB(self.db, 0)
122 self.assertURIs(
123 [
124 "gs://example/gtk+/public1.tbz2",
125 "gs://example/gtk+/foo.tgz",
126 "gs://example/private.tbz2",
127 ]
128 )
David James8c846492011-01-25 17:07:29 -0800129
Alex Klein1699fab2022-09-08 08:46:06 -0600130 def testMissingSHA1(self):
131 """Test population of the duplicate DB with a missing SHA1."""
132 del self.pkgindex.packages[0]["SHA1"]
133 self.pkgindex._PopulateDuplicateDB(self.db, 0)
134 self.assertURIs(
135 ["gs://example/gtk+/foo.tgz", "gs://example/private.tbz2"]
136 )
David James8c846492011-01-25 17:07:29 -0800137
Alex Klein1699fab2022-09-08 08:46:06 -0600138 def testFailedPopulate(self):
139 """Test failure conditions for the populate method."""
140 headerless = SimplePackageIndex(header=False)
141 self.assertRaises(KeyError, headerless._PopulateDuplicateDB, self.db, 0)
142 del self.pkgindex.packages[0]["CPV"]
143 self.assertRaises(
144 KeyError, self.pkgindex._PopulateDuplicateDB, self.db, 0
145 )
David James8c846492011-01-25 17:07:29 -0800146
147
Mike Frysinger68182472014-11-05 22:38:39 -0500148class TestResolveDuplicateUploads(cros_test_lib.MockTestCase, TestPkgIndex):
Alex Klein1699fab2022-09-08 08:46:06 -0600149 """Tests for the ResolveDuplicateUploads function."""
David James8c846492011-01-25 17:07:29 -0800150
Alex Klein1699fab2022-09-08 08:46:06 -0600151 def setUp(self):
152 self.PatchObject(binpkg.time, "time", return_value=binpkg.TWO_WEEKS)
153 self.db = {}
154 self.dup = SimplePackageIndex()
155 self.expected_pkgindex = SimplePackageIndex()
David James2c7ccb42012-11-04 15:34:28 -0800156
Alex Klein1699fab2022-09-08 08:46:06 -0600157 def assertNoDuplicates(self, candidates):
158 """Verify no duplicates are found with the specified candidates."""
159 uploads = self.pkgindex.ResolveDuplicateUploads(candidates)
160 self.assertEqual(uploads, self.pkgindex.packages)
161 self.assertEqual(
162 len(self.pkgindex.packages), len(self.expected_pkgindex.packages)
163 )
164 for pkg1, pkg2 in zip(
165 self.pkgindex.packages, self.expected_pkgindex.packages
166 ):
167 self.assertNotEqual(pkg1["MTIME"], pkg2["MTIME"])
168 del pkg1["MTIME"]
169 del pkg2["MTIME"]
170 self.assertEqual(self.pkgindex.modified, False)
171 self.assertEqual(
172 self.pkgindex.packages, self.expected_pkgindex.packages
173 )
David James2c7ccb42012-11-04 15:34:28 -0800174
Alex Klein1699fab2022-09-08 08:46:06 -0600175 def assertAllDuplicates(self, candidates):
176 """Verify every package is a duplicate in the specified list."""
177 for pkg in self.expected_pkgindex.packages:
178 pkg.setdefault("PATH", pkg["CPV"] + ".tbz2")
179 self.pkgindex.ResolveDuplicateUploads(candidates)
180 self.assertEqual(
181 self.pkgindex.packages, self.expected_pkgindex.packages
182 )
David James615e5b52011-06-03 11:10:15 -0700183
Alex Klein1699fab2022-09-08 08:46:06 -0600184 def testEmptyList(self):
185 """If no candidates are supplied, no duplicates should be found."""
186 self.assertNoDuplicates([])
David James8c846492011-01-25 17:07:29 -0800187
Alex Klein1699fab2022-09-08 08:46:06 -0600188 def testEmptyIndex(self):
189 """If no packages are supplied, no duplicates should be found."""
190 self.assertNoDuplicates([self.empty])
David James8c846492011-01-25 17:07:29 -0800191
Alex Klein1699fab2022-09-08 08:46:06 -0600192 def testDifferentURI(self):
193 """If the URI differs, no duplicates should be found."""
194 self.dup.header["URI"] = "gs://example2"
195 self.assertNoDuplicates([self.dup])
David James2c7ccb42012-11-04 15:34:28 -0800196
Alex Klein1699fab2022-09-08 08:46:06 -0600197 def testUpdateModificationTime(self):
198 """When duplicates are found, we should use the latest mtime."""
199 for pkg in self.expected_pkgindex.packages:
200 pkg["MTIME"] = "10"
201 for pkg in self.dup.packages:
202 pkg["MTIME"] = "4"
203 self.assertAllDuplicates([self.expected_pkgindex, self.dup])
David James2c7ccb42012-11-04 15:34:28 -0800204
Alex Klein1699fab2022-09-08 08:46:06 -0600205 def testCanonicalUrl(self):
Trent Apted3abd3d22023-05-17 11:40:51 +1000206 """If the URL is in a different format, should still find duplicates."""
Alex Klein1699fab2022-09-08 08:46:06 -0600207 self.dup.header["URI"] = gs.PUBLIC_BASE_HTTPS_URL + "example"
208 self.assertAllDuplicates([self.dup])
David James8c846492011-01-25 17:07:29 -0800209
Alex Klein1699fab2022-09-08 08:46:06 -0600210 def testMissingSHA1(self):
211 """We should not find duplicates if there is no SHA1."""
212 del self.pkgindex.packages[0]["SHA1"]
213 del self.expected_pkgindex.packages[0]["SHA1"]
214 for pkg in self.expected_pkgindex.packages[1:]:
215 pkg.setdefault("PATH", pkg["CPV"] + ".tbz2")
216 self.pkgindex.ResolveDuplicateUploads([self.dup])
217 self.assertNotEqual(
218 self.pkgindex.packages[0]["MTIME"],
219 self.expected_pkgindex.packages[0]["MTIME"],
220 )
221 del self.pkgindex.packages[0]["MTIME"]
222 del self.expected_pkgindex.packages[0]["MTIME"]
223 self.assertEqual(
224 self.pkgindex.packages, self.expected_pkgindex.packages
225 )
David James8c846492011-01-25 17:07:29 -0800226
Alex Klein1699fab2022-09-08 08:46:06 -0600227 def testSymbolsAvailable(self):
Trent Apted3abd3d22023-05-17 11:40:51 +1000228 """If symbols are available remotely: re-use them, set DEBUG_SYMBOLS."""
Alex Klein1699fab2022-09-08 08:46:06 -0600229 self.dup.packages[0]["DEBUG_SYMBOLS"] = "yes"
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800230
Alex Klein1699fab2022-09-08 08:46:06 -0600231 uploads = self.pkgindex.ResolveDuplicateUploads([self.dup])
232 self.assertEqual(uploads, [])
233 self.assertEqual(self.pkgindex.packages[0].get("DEBUG_SYMBOLS"), "yes")
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800234
Alex Klein1699fab2022-09-08 08:46:06 -0600235 def testSymbolsAvailableLocallyOnly(self):
236 """If the symbols are only available locally, reupload them."""
237 self.pkgindex.packages[0]["DEBUG_SYMBOLS"] = "yes"
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800238
Alex Klein1699fab2022-09-08 08:46:06 -0600239 uploads = self.pkgindex.ResolveDuplicateUploads([self.dup])
240 self.assertEqual(uploads, [self.pkgindex.packages[0]])
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800241
David James8c846492011-01-25 17:07:29 -0800242
Mike Frysinger68182472014-11-05 22:38:39 -0500243class TestWritePackageIndex(cros_test_lib.MockTestCase, TestPkgIndex):
Alex Klein1699fab2022-09-08 08:46:06 -0600244 """Tests for the WriteToNamedTemporaryFile function."""
David James8c846492011-01-25 17:07:29 -0800245
Alex Klein1699fab2022-09-08 08:46:06 -0600246 def testSimple(self):
247 """Test simple call of WriteToNamedTemporaryFile()"""
248 self.PatchObject(self.pkgindex, "Write")
249 f = self.pkgindex.WriteToNamedTemporaryFile()
250 self.assertEqual(f.read(), "")
David James8c846492011-01-25 17:07:29 -0800251
252
Mike Frysinger36870f92015-04-12 02:59:55 -0400253class TestUploadPrebuilt(cros_test_lib.MockTempDirTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600254 """Tests for the _UploadPrebuilt function."""
David James05bcb2b2011-02-09 09:25:47 -0800255
Alex Klein1699fab2022-09-08 08:46:06 -0600256 def setUp(self):
257 class MockTemporaryFile(object):
258 """Mock out the temporary file logic."""
David James05bcb2b2011-02-09 09:25:47 -0800259
Alex Klein1699fab2022-09-08 08:46:06 -0600260 def __init__(self, name):
261 self.name = name
262
263 self.pkgindex = SimplePackageIndex()
264 self.PatchObject(
265 binpkg, "GrabLocalPackageIndex", return_value=self.pkgindex
266 )
267 self.PatchObject(
268 self.pkgindex,
269 "ResolveDuplicateUploads",
270 return_value=PRIVATE_PACKAGES,
271 )
272 self.PatchObject(
273 self.pkgindex,
274 "WriteToNamedTemporaryFile",
275 return_value=MockTemporaryFile("fake"),
276 )
277 self.remote_up_mock = self.PatchObject(prebuilt, "RemoteUpload")
278 self.gs_up_mock = self.PatchObject(prebuilt, "_GsUpload")
279
280 def testSuccessfulGsUpload(self):
281 uploads = {
282 os.path.join(self.tempdir, "private.tbz2"): "gs://foo/private.tbz2"
283 }
284 dev_extras = os.path.join(self.tempdir, "dev-only-extras.tar.xz")
285 osutils.Touch(dev_extras)
286 self.PatchObject(prebuilt, "GenerateUploadDict", return_value=uploads)
287 uploads = uploads.copy()
288 uploads["fake"] = "gs://foo/suffix/Packages"
289 uploads[dev_extras] = "gs://foo/suffix/dev-only-extras.tar.xz"
290 acl = "public-read"
291 uri = self.pkgindex.header["URI"]
292 uploader = prebuilt.PrebuiltUploader(
293 "gs://foo",
294 acl,
295 uri,
296 [],
297 "/",
298 [],
299 False,
300 "foo",
301 False,
302 "x86-foo",
303 [],
304 "",
Bob Haarmanc0082602022-09-20 16:12:43 -0700305 report={},
Alex Klein1699fab2022-09-08 08:46:06 -0600306 )
307 uploader._UploadPrebuilt(self.tempdir, "suffix")
308 self.remote_up_mock.assert_called_once_with(mock.ANY, acl, uploads)
309 self.assertTrue(self.gs_up_mock.called)
David James05bcb2b2011-02-09 09:25:47 -0800310
David James05bcb2b2011-02-09 09:25:47 -0800311
Greg Edelston64620d12023-02-23 15:29:49 -0700312class TestUpdateRemoteSdkLatestFile(cros_test_lib.MockTestCase):
313 """Tests for PrebuiltUploader._UpdateRemoteSdkLatestFile."""
314
315 def setUp(self):
316 self._write_file_patch = self.PatchObject(osutils, "WriteFile")
317 self.PatchObject(prebuilt.PrebuiltUploader, "_Upload")
318 self.PatchObject(
319 gs.GSContext,
320 "LoadKeyValueStore",
321 return_value={
322 "LATEST_SDK": "1000",
323 "LATEST_SDK_UPREV_TARGET": "2000",
324 },
325 )
326 self._uploader = prebuilt.PrebuiltUploader(
327 "gs://foo",
328 "public-read",
329 SimplePackageIndex().header["URI"],
330 [],
331 "/",
332 [],
333 False,
334 "foo",
335 False,
336 "x86-foo",
337 [],
338 "",
339 report={},
340 )
341
342 def testNoChanges(self):
343 self._uploader._UpdateRemoteSdkLatestFile()
344 expected = prebuilt.PrebuiltUploader._CreateRemoteSdkLatestFileContents(
345 "1000", "2000"
346 )
347 self._write_file_patch.assert_called_with(mock.ANY, expected)
348
349 def testChangeLatestSdk(self):
350 self._uploader._UpdateRemoteSdkLatestFile(latest_sdk="3000")
351 expected = prebuilt.PrebuiltUploader._CreateRemoteSdkLatestFileContents(
352 "3000", "2000"
353 )
354 self._write_file_patch.assert_called_with(mock.ANY, expected)
355
356 def testChangeLatestUprevTarget(self):
357 self._uploader._UpdateRemoteSdkLatestFile(
358 latest_sdk_uprev_target="4000"
359 )
360 expected = prebuilt.PrebuiltUploader._CreateRemoteSdkLatestFileContents(
361 "1000", "4000"
362 )
363 self._write_file_patch.assert_called_with(mock.ANY, expected)
364
365 def testChangeBoth(self):
366 self._uploader._UpdateRemoteSdkLatestFile(
367 latest_sdk="3000", latest_sdk_uprev_target="4000"
368 )
369 expected = prebuilt.PrebuiltUploader._CreateRemoteSdkLatestFileContents(
370 "3000", "4000"
371 )
372 self._write_file_patch.assert_called_with(mock.ANY, expected)
373
374
Mike Frysinger36870f92015-04-12 02:59:55 -0400375class TestSyncPrebuilts(cros_test_lib.MockTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600376 """Tests for the SyncHostPrebuilts function."""
David James05bcb2b2011-02-09 09:25:47 -0800377
Alex Klein1699fab2022-09-08 08:46:06 -0600378 def setUp(self):
Bob Haarmanc0082602022-09-20 16:12:43 -0700379 clnum = [1]
380
381 def mock_rev(_filename, _data, report, *_args, **_kwargs):
382 report.setdefault("created_cls", []).append(
383 f"https://crrev.com/unittest/{clnum[0]}"
384 )
385 clnum[0] += 1
386
Alex Klein1699fab2022-09-08 08:46:06 -0600387 self.rev_mock = self.PatchObject(
Greg Edelston86aea7b2023-02-15 16:50:25 -0700388 binpkg,
389 "UpdateAndSubmitKeyValueFile",
Bob Haarmanc0082602022-09-20 16:12:43 -0700390 side_effect=mock_rev,
Alex Klein1699fab2022-09-08 08:46:06 -0600391 )
392 self.update_binhost_mock = self.PatchObject(
393 prebuilt, "UpdateBinhostConfFile", return_value=None
394 )
395 self.build_path = "/trunk"
396 self.upload_location = "gs://upload/"
397 self.version = "1"
398 self.binhost = "http://prebuilt/"
399 self.key = "PORTAGE_BINHOST"
400 self.upload_mock = self.PatchObject(
401 prebuilt.PrebuiltUploader, "_UploadPrebuilt", return_value=True
402 )
David James05bcb2b2011-02-09 09:25:47 -0800403
Alex Klein1699fab2022-09-08 08:46:06 -0600404 def _testSyncHostPrebuilts(self, chroot):
405 board = "x86-foo"
406 target = prebuilt.BuildTarget(board, "aura")
407 slave_targets = [prebuilt.BuildTarget("x86-bar", "aura")]
Bob Haarmanc0082602022-09-20 16:12:43 -0700408 report = {}
Alex Klein1699fab2022-09-08 08:46:06 -0600409 if chroot is None:
410 package_path = os.path.join(
411 self.build_path, "chroot", prebuilt._HOST_PACKAGES_PATH
412 )
413 else:
414 package_path = os.path.join(chroot, prebuilt._HOST_PACKAGES_PATH)
415 url_suffix = prebuilt._REL_HOST_PATH % {
416 "version": self.version,
417 "host_arch": prebuilt._HOST_ARCH,
418 "target": target,
419 }
420 packages_url_suffix = "%s/packages" % url_suffix.rstrip("/")
421 url_value = "%s/%s/" % (
422 self.binhost.rstrip("/"),
423 packages_url_suffix.rstrip("/"),
424 )
425 urls = [url_value.replace("foo", "bar"), url_value]
426 binhost = " ".join(urls)
427 uploader = prebuilt.PrebuiltUploader(
428 self.upload_location,
429 "public-read",
430 self.binhost,
431 [],
432 self.build_path,
433 [],
434 False,
435 "foo",
436 False,
437 target,
438 slave_targets,
439 self.version,
Bob Haarmanc0082602022-09-20 16:12:43 -0700440 report,
Alex Klein1699fab2022-09-08 08:46:06 -0600441 chroot=chroot,
442 )
443 uploader.SyncHostPrebuilts(self.key, True, True)
Bob Haarmanc0082602022-09-20 16:12:43 -0700444 self.assertEqual(
445 report,
446 {
447 "created_cls": ["https://crrev.com/unittest/1"],
448 },
449 )
Alex Klein1699fab2022-09-08 08:46:06 -0600450 self.upload_mock.assert_called_once_with(
451 package_path, packages_url_suffix
452 )
453 self.rev_mock.assert_called_once_with(
Bob Haarmanc0082602022-09-20 16:12:43 -0700454 mock.ANY, {self.key: binhost}, report, dryrun=False
Alex Klein1699fab2022-09-08 08:46:06 -0600455 )
456 self.update_binhost_mock.assert_called_once_with(
457 mock.ANY, self.key, binhost
458 )
David James05bcb2b2011-02-09 09:25:47 -0800459
Alex Klein1699fab2022-09-08 08:46:06 -0600460 def testSyncHostPrebuilts(self):
461 self._testSyncHostPrebuilts(chroot=None)
Bob Haarmand1225ea2022-01-19 22:01:42 +0000462
Alex Klein1699fab2022-09-08 08:46:06 -0600463 def testSyncHostPrebuiltsWithChroot(self):
464 self._testSyncHostPrebuilts("/test/chroot")
Bob Haarmand1225ea2022-01-19 22:01:42 +0000465
Alex Klein1699fab2022-09-08 08:46:06 -0600466 def testSyncBoardPrebuilts(self):
467 board = "x86-foo"
468 target = prebuilt.BuildTarget(board, "aura")
469 slave_targets = [prebuilt.BuildTarget("x86-bar", "aura")]
470 board_path = os.path.join(
471 self.build_path, prebuilt._BOARD_PATH % {"board": board}
472 )
473 package_path = os.path.join(board_path, "packages")
474 url_suffix = prebuilt._REL_BOARD_PATH % {
475 "version": self.version,
476 "target": target,
477 }
478 packages_url_suffix = "%s/packages" % url_suffix.rstrip("/")
479 url_value = "%s/%s/" % (
480 self.binhost.rstrip("/"),
481 packages_url_suffix.rstrip("/"),
482 )
483 bar_binhost = url_value.replace("foo", "bar")
484 determine_mock = self.PatchObject(
485 prebuilt, "DeterminePrebuiltConfFile", side_effect=("bar", "foo")
486 )
487 self.PatchObject(prebuilt.PrebuiltUploader, "_UploadSdkTarball")
Bob Haarmanc0082602022-09-20 16:12:43 -0700488 report = {}
Alex Klein1699fab2022-09-08 08:46:06 -0600489 with parallel_unittest.ParallelMock():
490 multiprocessing.Process.exitcode = 0
491 uploader = prebuilt.PrebuiltUploader(
492 self.upload_location,
493 "public-read",
494 self.binhost,
495 [],
496 self.build_path,
497 [],
498 False,
499 "foo",
500 False,
501 target,
502 slave_targets,
503 self.version,
Bob Haarmanc0082602022-09-20 16:12:43 -0700504 report,
Alex Klein1699fab2022-09-08 08:46:06 -0600505 )
506 uploader.SyncBoardPrebuilts(
Greg Edelston8da51ce2023-03-22 10:40:59 -0600507 self.key, True, True, True, None, None, None, None, None, True
Alex Klein1699fab2022-09-08 08:46:06 -0600508 )
509 determine_mock.assert_has_calls(
510 [
511 mock.call(self.build_path, slave_targets[0]),
512 mock.call(self.build_path, target),
513 ]
514 )
515 self.upload_mock.assert_called_once_with(
516 package_path, packages_url_suffix
517 )
518 self.rev_mock.assert_has_calls(
519 [
Bob Haarmanc0082602022-09-20 16:12:43 -0700520 mock.call(
521 "bar",
522 {self.key: bar_binhost},
523 {
524 "created_cls": [
525 "https://crrev.com/unittest/1",
526 "https://crrev.com/unittest/2",
527 ],
528 },
529 dryrun=False,
530 ),
531 mock.call(
532 "foo",
533 {self.key: url_value},
534 {
535 "created_cls": [
536 "https://crrev.com/unittest/1",
537 "https://crrev.com/unittest/2",
538 ],
539 },
540 dryrun=False,
541 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600542 ]
543 )
544 self.update_binhost_mock.assert_has_calls(
545 [
546 mock.call(mock.ANY, self.key, bar_binhost),
547 mock.call(mock.ANY, self.key, url_value),
548 ]
549 )
David James05bcb2b2011-02-09 09:25:47 -0800550
551
Mike Frysinger36870f92015-04-12 02:59:55 -0400552class TestMain(cros_test_lib.MockTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600553 """Tests for the main() function."""
David Jamesc0f158a2011-02-22 16:07:29 -0800554
Alex Klein1699fab2022-09-08 08:46:06 -0600555 def testMain(self):
556 """Test that the main function works."""
Bob Haarman35460c22022-11-08 00:11:59 +0000557 # Use a real object as returned from ParseOptions as a spec for
558 # the mock options object, so that we don't have any properties
559 # that the real object doesn't have.
560 options_spec, _ = prebuilt.ParseOptions(
561 [
562 "--dry-run",
563 "--build-path",
564 "/trunk",
565 "-u",
566 "gs://upload",
567 ]
568 )
569 options = mock.MagicMock(spec=options_spec)
Alex Klein1699fab2022-09-08 08:46:06 -0600570 old_binhost = "http://prebuilt/1"
571 options.previous_binhost_url = [old_binhost]
572 options.board = "x86-foo"
573 options.profile = None
574 target = prebuilt.BuildTarget(options.board, options.profile)
575 options.build_path = "/trunk"
576 options.chroot = None
577 options.dryrun = False
578 options.private = True
579 options.packages = []
580 options.sync_host = True
581 options.git_sync = True
Greg Edelston8da51ce2023-03-22 10:40:59 -0600582 options.sync_remote_latest_sdk_file = True
Alex Klein1699fab2022-09-08 08:46:06 -0600583 options.upload_board_tarball = True
584 options.prepackaged_tarball = None
585 options.toolchains_overlay_tarballs = []
586 options.toolchains_overlay_upload_path = ""
587 options.toolchain_tarballs = []
588 options.toolchain_upload_path = ""
589 options.upload = "gs://upload/"
590 options.binhost_base_url = options.upload
591 options.prepend_version = True
592 options.set_version = None
593 options.skip_upload = False
594 options.filters = True
595 options.key = "PORTAGE_BINHOST"
596 options.binhost_conf_dir = None
597 options.sync_binhost_conf = True
598 options.slave_targets = [prebuilt.BuildTarget("x86-bar", "aura")]
599 self.PatchObject(
600 prebuilt, "ParseOptions", return_value=tuple([options, target])
601 )
602 self.PatchObject(binpkg, "GrabRemotePackageIndex", return_value=True)
603 init_mock = self.PatchObject(
604 prebuilt.PrebuiltUploader, "__init__", return_value=None
605 )
606 expected_gs_acl_path = os.path.join(
607 "/fake_path", prebuilt._GOOGLESTORAGE_GSUTIL_FILE
608 )
609 self.PatchObject(
610 portage_util, "FindOverlayFile", return_value=expected_gs_acl_path
611 )
612 host_mock = self.PatchObject(
613 prebuilt.PrebuiltUploader, "SyncHostPrebuilts", return_value=None
614 )
615 board_mock = self.PatchObject(
616 prebuilt.PrebuiltUploader, "SyncBoardPrebuilts", return_value=None
617 )
Mike Frysinger36870f92015-04-12 02:59:55 -0400618
Alex Klein1699fab2022-09-08 08:46:06 -0600619 prebuilt.main([])
Mike Frysinger36870f92015-04-12 02:59:55 -0400620
Alex Klein1699fab2022-09-08 08:46:06 -0600621 init_mock.assert_called_once_with(
622 options.upload,
623 expected_gs_acl_path,
624 options.upload,
625 mock.ANY,
626 options.build_path,
627 options.packages,
628 False,
629 None,
630 False,
631 target,
632 options.slave_targets,
633 mock.ANY,
Bob Haarmanc0082602022-09-20 16:12:43 -0700634 {},
Alex Klein1699fab2022-09-08 08:46:06 -0600635 None,
636 )
637 board_mock.assert_called_once_with(
638 options.key,
639 options.git_sync,
640 options.sync_binhost_conf,
641 options.upload_board_tarball,
642 None,
643 [],
644 "",
645 [],
646 "",
Greg Edelston8da51ce2023-03-22 10:40:59 -0600647 options.sync_remote_latest_sdk_file,
Alex Klein1699fab2022-09-08 08:46:06 -0600648 )
649 host_mock.assert_called_once_with(
650 options.key, options.git_sync, options.sync_binhost_conf
651 )
David Jamesc0f158a2011-02-22 16:07:29 -0800652
Mike Frysinger9e979b92012-11-29 02:55:09 -0500653
Mike Frysinger68182472014-11-05 22:38:39 -0500654class TestSdk(cros_test_lib.MockTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600655 """Test logic related to uploading SDK binaries"""
Mike Frysinger9e979b92012-11-29 02:55:09 -0500656
Alex Klein1699fab2022-09-08 08:46:06 -0600657 def setUp(self):
658 self.PatchObject(
659 prebuilt,
660 "_GsUpload",
661 side_effect=Exception("should not get called"),
662 )
663 self.PatchObject(
664 prebuilt,
665 "UpdateBinhostConfFile",
666 side_effect=Exception("should not get called"),
667 )
Greg Edelston64620d12023-02-23 15:29:49 -0700668 self.PatchObject(
669 gs.GSContext,
670 "LoadKeyValueStore",
671 return_value={
672 "LATEST_SDK": "1000",
673 "LATEST_SDK_UPREV_TARGET": "2000",
674 },
675 )
Greg Edelstonf3916f92023-02-22 15:49:38 -0700676 self.write_file_mock = self.PatchObject(osutils, "WriteFile")
Alex Klein1699fab2022-09-08 08:46:06 -0600677 self.upload_mock = self.PatchObject(
678 prebuilt.PrebuiltUploader, "_Upload"
679 )
Mike Frysinger9e979b92012-11-29 02:55:09 -0500680
Alex Klein1699fab2022-09-08 08:46:06 -0600681 self.acl = "magic-acl"
Mike Frysinger9e979b92012-11-29 02:55:09 -0500682
Alex Klein1699fab2022-09-08 08:46:06 -0600683 # All these args pretty much get ignored. Whee.
684 self.uploader = prebuilt.PrebuiltUploader(
685 "gs://foo",
686 self.acl,
687 "prebuilt",
688 [],
689 "/",
690 [],
691 False,
692 "foo",
693 False,
694 "x86-foo",
695 [],
696 "chroot-1234",
Bob Haarmanc0082602022-09-20 16:12:43 -0700697 report={},
Alex Klein1699fab2022-09-08 08:46:06 -0600698 )
Mike Frysinger9e979b92012-11-29 02:55:09 -0500699
Alex Klein1699fab2022-09-08 08:46:06 -0600700 def testSdkUpload(
701 self,
702 to_tarballs=(),
703 to_upload_path=None,
704 tc_tarballs=(),
705 tc_upload_path=None,
706 ):
707 """Make sure we can upload just an SDK tarball"""
708 tar = "sdk.tar.xz"
709 ver = "1234"
710 vtar = "cros-sdk-%s.tar.xz" % ver
Mike Frysinger9e979b92012-11-29 02:55:09 -0500711
Greg Edelstonf3916f92023-02-22 15:49:38 -0700712 upload_calls = [
Alex Klein1699fab2022-09-08 08:46:06 -0600713 mock.call(
714 "%s.Manifest" % tar, "gs://chromiumos-sdk/%s.Manifest" % vtar
715 ),
716 mock.call(tar, "gs://chromiumos-sdk/%s" % vtar),
717 ]
718 for to in to_tarballs:
719 to = to.split(":")
Greg Edelstonf3916f92023-02-22 15:49:38 -0700720 upload_calls.append(
Alex Klein1699fab2022-09-08 08:46:06 -0600721 mock.call(
722 to[1],
723 ("gs://chromiumos-sdk/" + to_upload_path)
724 % {"toolchains": to[0]},
725 )
726 )
727 for tc in tc_tarballs:
728 tc = tc.split(":")
Greg Edelstonf3916f92023-02-22 15:49:38 -0700729 upload_calls.append(
Alex Klein1699fab2022-09-08 08:46:06 -0600730 mock.call(
731 tc[1],
732 ("gs://chromiumos-sdk/" + tc_upload_path)
733 % {"target": tc[0]},
734 )
735 )
Greg Edelstonf3916f92023-02-22 15:49:38 -0700736 upload_calls.append(
Alex Klein1699fab2022-09-08 08:46:06 -0600737 mock.call(mock.ANY, "gs://chromiumos-sdk/cros-sdk-latest.conf")
738 )
Mike Frysinger9e979b92012-11-29 02:55:09 -0500739
Alex Klein1699fab2022-09-08 08:46:06 -0600740 self.uploader._UploadSdkTarball(
741 "amd64-host",
742 "",
743 tar,
744 to_tarballs,
745 to_upload_path,
746 tc_tarballs,
747 tc_upload_path,
Greg Edelston8da51ce2023-03-22 10:40:59 -0600748 True,
Alex Klein1699fab2022-09-08 08:46:06 -0600749 )
Greg Edelstonf3916f92023-02-22 15:49:38 -0700750 self.upload_mock.assert_has_calls(upload_calls)
751
752 expected_latest_file_contents = f"""\
753# The most recent SDK that is tested and ready for use.
754LATEST_SDK="{ver}"
755
756# The most recently built version. New uprev attempts should target this.
757# Warning: This version may not be tested yet.
Greg Edelston64620d12023-02-23 15:29:49 -0700758LATEST_SDK_UPREV_TARGET=\"2000\""""
Greg Edelstonf3916f92023-02-22 15:49:38 -0700759 self.write_file_mock.assert_any_call(
760 mock.ANY, expected_latest_file_contents
761 )
Mike Frysinger9e979b92012-11-29 02:55:09 -0500762
Alex Klein1699fab2022-09-08 08:46:06 -0600763 def testBoardOverlayTarballUpload(self):
764 """Make sure processing of board-specific overlay tarballs works."""
765 to_tarballs = (
766 (
Trent Aptedc4f366a2023-05-16 15:32:48 +1000767 "i686-pc-linux-gnu:/some/path/built-sdk-overlay-toolchains-"
768 "i686-pc-linux-gnu.tar.xz"
Alex Klein1699fab2022-09-08 08:46:06 -0600769 ),
770 (
Trent Aptedc4f366a2023-05-16 15:32:48 +1000771 "armv7a-cros-linux-gnueabi-arm-none-eabi:/some/path/built-sdk-"
772 "overlay-toolchains-armv7a-cros-linux-gnueabi-arm-none-eabi"
Alex Klein1699fab2022-09-08 08:46:06 -0600773 ),
774 )
Trent Aptedc4f366a2023-05-16 15:32:48 +1000775 to_upload_path = (
776 "1994/04/cros-sdk-overlay-toolchains-%(toolchains)s-1994.04.02."
777 "tar.xz"
778 )
Alex Klein1699fab2022-09-08 08:46:06 -0600779 self.testSdkUpload(
780 to_tarballs=to_tarballs, to_upload_path=to_upload_path
781 )
Gilad Arnoldad333182015-05-27 15:50:41 -0700782
Alex Klein1699fab2022-09-08 08:46:06 -0600783 def testToolchainTarballUpload(self):
784 """Make sure processing of toolchain tarballs works."""
785 tc_tarballs = (
786 "i686:/some/i686.tar.xz",
787 "arm-none:/some/arm.tar.xz",
788 )
789 tc_upload_path = "1994/04/%(target)s-1994.04.02.tar.xz"
790 self.testSdkUpload(
791 tc_tarballs=tc_tarballs, tc_upload_path=tc_upload_path
792 )
Greg Edelston325e4412023-05-04 16:22:10 -0600793
794
795@pytest.mark.parametrize(
796 "extra_args,expected_sync",
797 [
798 ([], True),
799 (["--sync-remote-latest-sdk-file"], True),
800 (["--no-sync-remote-latest-sdk-file"], False),
801 (
802 [
803 "--no-sync-remote-latest-sdk-file",
804 "--sync-remote-latest-sdk-file",
805 ],
806 True,
807 ),
808 (
809 [
810 "--sync-remote-latest-sdk-file",
811 "--no-sync-remote-latest-sdk-file",
812 ],
813 False,
814 ),
815 ],
816)
817def test_parse_options_sync_remote_latest_file(
818 extra_args: List[str],
819 expected_sync: bool,
820):
821 """Test --sync-remote-latest-file and --no-sync-remote-latest-file.
822
823 Desired behavior:
824 * If either of those args is given, take the last one.
825 * If neither is given, default to True.
826
827 Args:
828 extra_args: Command-line args to pass into parse_options() besides the
829 bare minimum.
830 expected_sync: Whether options.sync_remote_latest_file should be True.
831 """
832 # Bare minimum args to run upload_prebuilts
833 args = ["--build-path", "/foo", "-u", "gs://foo/bar"]
834 args.extend(extra_args)
835 options, _ = prebuilt.ParseOptions(args)
836 assert options.sync_remote_latest_sdk_file == expected_sync