blob: 02faa294e6555246f8b4c1442624a58cf54b459b [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
David James8c846492011-01-25 17:07:29 -080010import tempfile
Mike Frysinger166fea02021-02-12 05:30:33 -050011from unittest import mock
Chris Sosa471532a2011-02-01 15:10:06 -080012
Mike Frysinger40ffb532021-02-12 07:36:08 -050013from chromite.lib import binpkg
Brian Harringc92788f2012-09-21 18:07:15 -070014from chromite.lib import cros_test_lib
David James2c7ccb42012-11-04 15:34:28 -080015from chromite.lib import gs
Zdenek Behanc0e18762012-09-22 04:06:17 +020016from chromite.lib import osutils
Mike Frysinger36870f92015-04-12 02:59:55 -040017from chromite.lib import parallel_unittest
Prathmesh Prabhu421eef22014-10-16 17:13:19 -070018from chromite.lib import portage_util
Mike Frysinger40ffb532021-02-12 07:36:08 -050019from chromite.scripts import upload_prebuilts as prebuilt
David James8c846492011-01-25 17:07:29 -080020
Mike Frysinger68182472014-11-05 22:38:39 -050021
Mike Frysinger27e21b72018-07-12 14:20:21 -040022# pylint: disable=protected-access
23
24
Alex Klein1699fab2022-09-08 08:46:06 -060025PUBLIC_PACKAGES = [
26 {"CPV": "gtk+/public1", "SHA1": "1", "MTIME": "1"},
27 {"CPV": "gtk+/public2", "SHA1": "2", "PATH": "gtk+/foo.tgz", "MTIME": "2"},
28]
29PRIVATE_PACKAGES = [{"CPV": "private", "SHA1": "3", "MTIME": "3"}]
David James8c846492011-01-25 17:07:29 -080030
31
32def SimplePackageIndex(header=True, packages=True):
Alex Klein1699fab2022-09-08 08:46:06 -060033 pkgindex = binpkg.PackageIndex()
34 if header:
35 pkgindex.header["URI"] = "gs://example"
36 if packages:
37 pkgindex.packages = copy.deepcopy(PUBLIC_PACKAGES + PRIVATE_PACKAGES)
38 return pkgindex
David James8c846492011-01-25 17:07:29 -080039
40
Brian Harringc92788f2012-09-21 18:07:15 -070041class TestUpdateFile(cros_test_lib.TempDirTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -060042 """Tests for the UpdateLocalFile function."""
David James8c846492011-01-25 17:07:29 -080043
Alex Klein1699fab2022-09-08 08:46:06 -060044 def setUp(self):
45 self.contents_str = [
46 "# comment that should be skipped",
47 'PKGDIR="/var/lib/portage/pkgs"',
48 'PORTAGE_BINHOST="http://no.thanks.com"',
49 "portage portage-20100310.tar.bz2",
50 'COMPILE_FLAGS="some_value=some_other"',
51 ]
52 self.version_file = os.path.join(self.tempdir, "version")
53 osutils.WriteFile(self.version_file, "\n".join(self.contents_str))
David James8c846492011-01-25 17:07:29 -080054
Alex Klein1699fab2022-09-08 08:46:06 -060055 def _read_version_file(self, version_file=None):
56 """Read the contents of self.version_file and return as a list."""
57 if not version_file:
58 version_file = self.version_file
David James8c846492011-01-25 17:07:29 -080059
Alex Klein1699fab2022-09-08 08:46:06 -060060 with open(version_file) as version_fh:
61 return [line.strip() for line in version_fh.readlines()]
Sergey Frolov89d28242022-06-06 17:49:20 -060062
Alex Klein1699fab2022-09-08 08:46:06 -060063 def _verify_key_pair(self, key, val):
64 file_contents = self._read_version_file()
David James8c846492011-01-25 17:07:29 -080065
Alex Klein1699fab2022-09-08 08:46:06 -060066 # Make sure 'key' entry is only found once.
67 entry_found = False
Sergey Frolov09280f12022-06-06 17:47:32 -060068
Alex Klein1699fab2022-09-08 08:46:06 -060069 # Ensure value is wrapped on quotes.
70 if '"' not in val:
71 val = '"%s"' % val
Sergey Frolov09280f12022-06-06 17:47:32 -060072
Alex Klein1699fab2022-09-08 08:46:06 -060073 # Inspect file contents.
74 for entry in file_contents:
75 if "=" not in entry:
76 continue
77 file_key, file_val = entry.split("=", maxsplit=1)
78 if file_key == key:
79 if val == file_val:
80 if entry_found:
81 self.fail(f"Variable {file_key} appears twice")
82 else:
83 entry_found = True
Sergey Frolov09280f12022-06-06 17:47:32 -060084
Alex Klein1699fab2022-09-08 08:46:06 -060085 if not entry_found:
86 self.fail('Could not find "%s=%s" in version file' % (key, val))
Sergey Frolov09280f12022-06-06 17:47:32 -060087
Alex Klein1699fab2022-09-08 08:46:06 -060088 def testAddVariableThatDoesNotExist(self):
89 """Add in a new variable that was no present in the file."""
90 key = "PORTAGE_BINHOST"
91 value = "1234567"
92 prebuilt.UpdateLocalFile(self.version_file, value)
93 print(self.version_file)
94 self._read_version_file()
95 self._verify_key_pair(key, value)
96 print(self.version_file)
David James8c846492011-01-25 17:07:29 -080097
Alex Klein1699fab2022-09-08 08:46:06 -060098 def testUpdateVariable(self):
99 """Test updating a variable that already exists."""
100 binhost_key, binhost_val = self.contents_str[2].split("=")
101 if binhost_key != "PORTAGE_BINHOST":
102 self.fail(
103 "unexpected test input: expected PORTAGE_BINHOST at line[2]"
104 )
105 self._verify_key_pair(binhost_key, binhost_val)
David James8c846492011-01-25 17:07:29 -0800106
Alex Klein1699fab2022-09-08 08:46:06 -0600107 # Confirm that unrelated variable 'PKGDIR' does not change.
108 pkgdir_key, pkgdir_val = self.contents_str[1].split("=")
109 if pkgdir_key != "PKGDIR":
110 self.fail("unexpected test input: expected PKGDIR at line[1]")
111 self._verify_key_pair(pkgdir_key, pkgdir_val)
Sergey Frolov09280f12022-06-06 17:47:32 -0600112
Alex Klein1699fab2022-09-08 08:46:06 -0600113 binhost_new_val = "test_update"
114 prebuilt.UpdateLocalFile(self.version_file, binhost_new_val)
115 self._verify_key_pair(binhost_key, binhost_new_val)
116 self._verify_key_pair(pkgdir_key, pkgdir_val)
Sergey Frolov09280f12022-06-06 17:47:32 -0600117
Alex Klein1699fab2022-09-08 08:46:06 -0600118 binhost_new_val = "test_update2"
119 prebuilt.UpdateLocalFile(self.version_file, binhost_new_val)
120 self._verify_key_pair(binhost_key, binhost_new_val)
121 self._verify_key_pair(pkgdir_key, pkgdir_val)
Sergey Frolov09280f12022-06-06 17:47:32 -0600122
Alex Klein1699fab2022-09-08 08:46:06 -0600123 def testUpdateNonExistentFile(self):
124 key = "PORTAGE_BINHOST"
125 value = "1234567"
126 non_existent_file = tempfile.mktemp()
127 try:
128 prebuilt.UpdateLocalFile(non_existent_file, value)
129 file_contents = self._read_version_file(non_existent_file)
130 self.assertEqual(file_contents, ['%s="%s"' % (key, value)])
131 finally:
132 if os.path.exists(non_existent_file):
133 os.remove(non_existent_file)
David James8c846492011-01-25 17:07:29 -0800134
135
Mike Frysinger68182472014-11-05 22:38:39 -0500136class TestPrebuilt(cros_test_lib.MockTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600137 """Tests for Prebuilt logic."""
David James8c846492011-01-25 17:07:29 -0800138
Alex Klein1699fab2022-09-08 08:46:06 -0600139 def setUp(self):
140 self._base_local_path = "/b/cbuild/build/chroot/build/x86-dogfood/"
141 self._gs_bucket_path = "gs://chromeos-prebuilt/host/version"
142 self._local_path = os.path.join(self._base_local_path, "public1.tbz2")
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800143
Alex Klein1699fab2022-09-08 08:46:06 -0600144 def testGenerateUploadDict(self):
145 self.PatchObject(prebuilt.os.path, "exists", return_true=True)
146 pkgs = [{"CPV": "public1"}]
147 result = prebuilt.GenerateUploadDict(
148 self._base_local_path, self._gs_bucket_path, pkgs
149 )
150 expected = {
151 self._local_path: self._gs_bucket_path + "/public1.tbz2",
152 }
153 self.assertEqual(result, expected)
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800154
Alex Klein1699fab2022-09-08 08:46:06 -0600155 def testGenerateUploadDictWithDebug(self):
156 self.PatchObject(prebuilt.os.path, "exists", return_true=True)
157 pkgs = [{"CPV": "public1", "DEBUG_SYMBOLS": "yes"}]
158 result = prebuilt.GenerateUploadDict(
159 self._base_local_path, self._gs_bucket_path, pkgs
160 )
161 expected = {
162 self._local_path: self._gs_bucket_path + "/public1.tbz2",
163 self._local_path.replace(
164 ".tbz2", ".debug.tbz2"
165 ): self._gs_bucket_path
166 + "/public1.debug.tbz2",
167 }
168 self.assertEqual(result, expected)
David James8c846492011-01-25 17:07:29 -0800169
Alex Klein1699fab2022-09-08 08:46:06 -0600170 def testDeterminePrebuiltConfHost(self):
171 """Test that the host prebuilt path comes back properly."""
172 expected_path = os.path.join(prebuilt._PREBUILT_MAKE_CONF["amd64"])
173 self.assertEqual(
174 prebuilt.DeterminePrebuiltConfFile("fake_path", "amd64"),
175 expected_path,
176 )
David James8c846492011-01-25 17:07:29 -0800177
David James8c846492011-01-25 17:07:29 -0800178
David James2c7ccb42012-11-04 15:34:28 -0800179class TestPkgIndex(cros_test_lib.TestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600180 """Helper for tests that update the Packages index file."""
David James2c7ccb42012-11-04 15:34:28 -0800181
Alex Klein1699fab2022-09-08 08:46:06 -0600182 def setUp(self):
183 self.db = {}
184 self.pkgindex = SimplePackageIndex()
185 self.empty = SimplePackageIndex(packages=False)
David James2c7ccb42012-11-04 15:34:28 -0800186
Alex Klein1699fab2022-09-08 08:46:06 -0600187 def assertURIs(self, uris):
188 """Verify that the duplicate DB has the specified URLs."""
189 expected = [v.uri for _, v in sorted(self.db.items())]
190 self.assertEqual(expected, uris)
David James2c7ccb42012-11-04 15:34:28 -0800191
192
193class TestPackagesFileFiltering(TestPkgIndex):
Alex Klein1699fab2022-09-08 08:46:06 -0600194 """Tests for Packages filtering behavior."""
David James8c846492011-01-25 17:07:29 -0800195
Alex Klein1699fab2022-09-08 08:46:06 -0600196 def testFilterPkgIndex(self):
197 """Test filtering out of private packages."""
198 self.pkgindex.RemoveFilteredPackages(
199 lambda pkg: pkg in PRIVATE_PACKAGES
200 )
201 self.assertEqual(self.pkgindex.packages, PUBLIC_PACKAGES)
202 self.assertEqual(self.pkgindex.modified, True)
David James8c846492011-01-25 17:07:29 -0800203
204
David James2c7ccb42012-11-04 15:34:28 -0800205class TestPopulateDuplicateDB(TestPkgIndex):
Alex Klein1699fab2022-09-08 08:46:06 -0600206 """Tests for the _PopulateDuplicateDB function."""
David James8c846492011-01-25 17:07:29 -0800207
Alex Klein1699fab2022-09-08 08:46:06 -0600208 def testEmptyIndex(self):
209 """Test population of the duplicate DB with an empty index."""
210 self.empty._PopulateDuplicateDB(self.db, 0)
211 self.assertEqual(self.db, {})
David James8c846492011-01-25 17:07:29 -0800212
Alex Klein1699fab2022-09-08 08:46:06 -0600213 def testNormalIndex(self):
214 """Test population of the duplicate DB with a full index."""
215 self.pkgindex._PopulateDuplicateDB(self.db, 0)
216 self.assertURIs(
217 [
218 "gs://example/gtk+/public1.tbz2",
219 "gs://example/gtk+/foo.tgz",
220 "gs://example/private.tbz2",
221 ]
222 )
David James8c846492011-01-25 17:07:29 -0800223
Alex Klein1699fab2022-09-08 08:46:06 -0600224 def testMissingSHA1(self):
225 """Test population of the duplicate DB with a missing SHA1."""
226 del self.pkgindex.packages[0]["SHA1"]
227 self.pkgindex._PopulateDuplicateDB(self.db, 0)
228 self.assertURIs(
229 ["gs://example/gtk+/foo.tgz", "gs://example/private.tbz2"]
230 )
David James8c846492011-01-25 17:07:29 -0800231
Alex Klein1699fab2022-09-08 08:46:06 -0600232 def testFailedPopulate(self):
233 """Test failure conditions for the populate method."""
234 headerless = SimplePackageIndex(header=False)
235 self.assertRaises(KeyError, headerless._PopulateDuplicateDB, self.db, 0)
236 del self.pkgindex.packages[0]["CPV"]
237 self.assertRaises(
238 KeyError, self.pkgindex._PopulateDuplicateDB, self.db, 0
239 )
David James8c846492011-01-25 17:07:29 -0800240
241
Mike Frysinger68182472014-11-05 22:38:39 -0500242class TestResolveDuplicateUploads(cros_test_lib.MockTestCase, TestPkgIndex):
Alex Klein1699fab2022-09-08 08:46:06 -0600243 """Tests for the ResolveDuplicateUploads function."""
David James8c846492011-01-25 17:07:29 -0800244
Alex Klein1699fab2022-09-08 08:46:06 -0600245 def setUp(self):
246 self.PatchObject(binpkg.time, "time", return_value=binpkg.TWO_WEEKS)
247 self.db = {}
248 self.dup = SimplePackageIndex()
249 self.expected_pkgindex = SimplePackageIndex()
David James2c7ccb42012-11-04 15:34:28 -0800250
Alex Klein1699fab2022-09-08 08:46:06 -0600251 def assertNoDuplicates(self, candidates):
252 """Verify no duplicates are found with the specified candidates."""
253 uploads = self.pkgindex.ResolveDuplicateUploads(candidates)
254 self.assertEqual(uploads, self.pkgindex.packages)
255 self.assertEqual(
256 len(self.pkgindex.packages), len(self.expected_pkgindex.packages)
257 )
258 for pkg1, pkg2 in zip(
259 self.pkgindex.packages, self.expected_pkgindex.packages
260 ):
261 self.assertNotEqual(pkg1["MTIME"], pkg2["MTIME"])
262 del pkg1["MTIME"]
263 del pkg2["MTIME"]
264 self.assertEqual(self.pkgindex.modified, False)
265 self.assertEqual(
266 self.pkgindex.packages, self.expected_pkgindex.packages
267 )
David James2c7ccb42012-11-04 15:34:28 -0800268
Alex Klein1699fab2022-09-08 08:46:06 -0600269 def assertAllDuplicates(self, candidates):
270 """Verify every package is a duplicate in the specified list."""
271 for pkg in self.expected_pkgindex.packages:
272 pkg.setdefault("PATH", pkg["CPV"] + ".tbz2")
273 self.pkgindex.ResolveDuplicateUploads(candidates)
274 self.assertEqual(
275 self.pkgindex.packages, self.expected_pkgindex.packages
276 )
David James615e5b52011-06-03 11:10:15 -0700277
Alex Klein1699fab2022-09-08 08:46:06 -0600278 def testEmptyList(self):
279 """If no candidates are supplied, no duplicates should be found."""
280 self.assertNoDuplicates([])
David James8c846492011-01-25 17:07:29 -0800281
Alex Klein1699fab2022-09-08 08:46:06 -0600282 def testEmptyIndex(self):
283 """If no packages are supplied, no duplicates should be found."""
284 self.assertNoDuplicates([self.empty])
David James8c846492011-01-25 17:07:29 -0800285
Alex Klein1699fab2022-09-08 08:46:06 -0600286 def testDifferentURI(self):
287 """If the URI differs, no duplicates should be found."""
288 self.dup.header["URI"] = "gs://example2"
289 self.assertNoDuplicates([self.dup])
David James2c7ccb42012-11-04 15:34:28 -0800290
Alex Klein1699fab2022-09-08 08:46:06 -0600291 def testUpdateModificationTime(self):
292 """When duplicates are found, we should use the latest mtime."""
293 for pkg in self.expected_pkgindex.packages:
294 pkg["MTIME"] = "10"
295 for pkg in self.dup.packages:
296 pkg["MTIME"] = "4"
297 self.assertAllDuplicates([self.expected_pkgindex, self.dup])
David James2c7ccb42012-11-04 15:34:28 -0800298
Alex Klein1699fab2022-09-08 08:46:06 -0600299 def testCanonicalUrl(self):
300 """If the URL is in a different format, we should still find duplicates."""
301 self.dup.header["URI"] = gs.PUBLIC_BASE_HTTPS_URL + "example"
302 self.assertAllDuplicates([self.dup])
David James8c846492011-01-25 17:07:29 -0800303
Alex Klein1699fab2022-09-08 08:46:06 -0600304 def testMissingSHA1(self):
305 """We should not find duplicates if there is no SHA1."""
306 del self.pkgindex.packages[0]["SHA1"]
307 del self.expected_pkgindex.packages[0]["SHA1"]
308 for pkg in self.expected_pkgindex.packages[1:]:
309 pkg.setdefault("PATH", pkg["CPV"] + ".tbz2")
310 self.pkgindex.ResolveDuplicateUploads([self.dup])
311 self.assertNotEqual(
312 self.pkgindex.packages[0]["MTIME"],
313 self.expected_pkgindex.packages[0]["MTIME"],
314 )
315 del self.pkgindex.packages[0]["MTIME"]
316 del self.expected_pkgindex.packages[0]["MTIME"]
317 self.assertEqual(
318 self.pkgindex.packages, self.expected_pkgindex.packages
319 )
David James8c846492011-01-25 17:07:29 -0800320
Alex Klein1699fab2022-09-08 08:46:06 -0600321 def testSymbolsAvailable(self):
322 """If symbols are available remotely, re-use them and set DEBUG_SYMBOLS."""
323 self.dup.packages[0]["DEBUG_SYMBOLS"] = "yes"
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800324
Alex Klein1699fab2022-09-08 08:46:06 -0600325 uploads = self.pkgindex.ResolveDuplicateUploads([self.dup])
326 self.assertEqual(uploads, [])
327 self.assertEqual(self.pkgindex.packages[0].get("DEBUG_SYMBOLS"), "yes")
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800328
Alex Klein1699fab2022-09-08 08:46:06 -0600329 def testSymbolsAvailableLocallyOnly(self):
330 """If the symbols are only available locally, reupload them."""
331 self.pkgindex.packages[0]["DEBUG_SYMBOLS"] = "yes"
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800332
Alex Klein1699fab2022-09-08 08:46:06 -0600333 uploads = self.pkgindex.ResolveDuplicateUploads([self.dup])
334 self.assertEqual(uploads, [self.pkgindex.packages[0]])
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800335
David James8c846492011-01-25 17:07:29 -0800336
Mike Frysinger68182472014-11-05 22:38:39 -0500337class TestWritePackageIndex(cros_test_lib.MockTestCase, TestPkgIndex):
Alex Klein1699fab2022-09-08 08:46:06 -0600338 """Tests for the WriteToNamedTemporaryFile function."""
David James8c846492011-01-25 17:07:29 -0800339
Alex Klein1699fab2022-09-08 08:46:06 -0600340 def testSimple(self):
341 """Test simple call of WriteToNamedTemporaryFile()"""
342 self.PatchObject(self.pkgindex, "Write")
343 f = self.pkgindex.WriteToNamedTemporaryFile()
344 self.assertEqual(f.read(), "")
David James8c846492011-01-25 17:07:29 -0800345
346
Mike Frysinger36870f92015-04-12 02:59:55 -0400347class TestUploadPrebuilt(cros_test_lib.MockTempDirTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600348 """Tests for the _UploadPrebuilt function."""
David James05bcb2b2011-02-09 09:25:47 -0800349
Alex Klein1699fab2022-09-08 08:46:06 -0600350 def setUp(self):
351 class MockTemporaryFile(object):
352 """Mock out the temporary file logic."""
David James05bcb2b2011-02-09 09:25:47 -0800353
Alex Klein1699fab2022-09-08 08:46:06 -0600354 def __init__(self, name):
355 self.name = name
356
357 self.pkgindex = SimplePackageIndex()
358 self.PatchObject(
359 binpkg, "GrabLocalPackageIndex", return_value=self.pkgindex
360 )
361 self.PatchObject(
362 self.pkgindex,
363 "ResolveDuplicateUploads",
364 return_value=PRIVATE_PACKAGES,
365 )
366 self.PatchObject(
367 self.pkgindex,
368 "WriteToNamedTemporaryFile",
369 return_value=MockTemporaryFile("fake"),
370 )
371 self.remote_up_mock = self.PatchObject(prebuilt, "RemoteUpload")
372 self.gs_up_mock = self.PatchObject(prebuilt, "_GsUpload")
373
374 def testSuccessfulGsUpload(self):
375 uploads = {
376 os.path.join(self.tempdir, "private.tbz2"): "gs://foo/private.tbz2"
377 }
378 dev_extras = os.path.join(self.tempdir, "dev-only-extras.tar.xz")
379 osutils.Touch(dev_extras)
380 self.PatchObject(prebuilt, "GenerateUploadDict", return_value=uploads)
381 uploads = uploads.copy()
382 uploads["fake"] = "gs://foo/suffix/Packages"
383 uploads[dev_extras] = "gs://foo/suffix/dev-only-extras.tar.xz"
384 acl = "public-read"
385 uri = self.pkgindex.header["URI"]
386 uploader = prebuilt.PrebuiltUploader(
387 "gs://foo",
388 acl,
389 uri,
390 [],
391 "/",
392 [],
393 False,
394 "foo",
395 False,
396 "x86-foo",
397 [],
398 "",
Bob Haarmanc0082602022-09-20 16:12:43 -0700399 report={},
Alex Klein1699fab2022-09-08 08:46:06 -0600400 )
401 uploader._UploadPrebuilt(self.tempdir, "suffix")
402 self.remote_up_mock.assert_called_once_with(mock.ANY, acl, uploads)
403 self.assertTrue(self.gs_up_mock.called)
David James05bcb2b2011-02-09 09:25:47 -0800404
David James05bcb2b2011-02-09 09:25:47 -0800405
Mike Frysinger36870f92015-04-12 02:59:55 -0400406class TestSyncPrebuilts(cros_test_lib.MockTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600407 """Tests for the SyncHostPrebuilts function."""
David James05bcb2b2011-02-09 09:25:47 -0800408
Alex Klein1699fab2022-09-08 08:46:06 -0600409 def setUp(self):
Bob Haarmanc0082602022-09-20 16:12:43 -0700410 clnum = [1]
411
412 def mock_rev(_filename, _data, report, *_args, **_kwargs):
413 report.setdefault("created_cls", []).append(
414 f"https://crrev.com/unittest/{clnum[0]}"
415 )
416 clnum[0] += 1
417
Alex Klein1699fab2022-09-08 08:46:06 -0600418 self.rev_mock = self.PatchObject(
Bob Haarmanc0082602022-09-20 16:12:43 -0700419 prebuilt,
420 "RevGitFile",
421 side_effect=mock_rev,
Alex Klein1699fab2022-09-08 08:46:06 -0600422 )
423 self.update_binhost_mock = self.PatchObject(
424 prebuilt, "UpdateBinhostConfFile", return_value=None
425 )
426 self.build_path = "/trunk"
427 self.upload_location = "gs://upload/"
428 self.version = "1"
429 self.binhost = "http://prebuilt/"
430 self.key = "PORTAGE_BINHOST"
431 self.upload_mock = self.PatchObject(
432 prebuilt.PrebuiltUploader, "_UploadPrebuilt", return_value=True
433 )
David James05bcb2b2011-02-09 09:25:47 -0800434
Alex Klein1699fab2022-09-08 08:46:06 -0600435 def _testSyncHostPrebuilts(self, chroot):
436 board = "x86-foo"
437 target = prebuilt.BuildTarget(board, "aura")
438 slave_targets = [prebuilt.BuildTarget("x86-bar", "aura")]
Bob Haarmanc0082602022-09-20 16:12:43 -0700439 report = {}
Alex Klein1699fab2022-09-08 08:46:06 -0600440 if chroot is None:
441 package_path = os.path.join(
442 self.build_path, "chroot", prebuilt._HOST_PACKAGES_PATH
443 )
444 else:
445 package_path = os.path.join(chroot, prebuilt._HOST_PACKAGES_PATH)
446 url_suffix = prebuilt._REL_HOST_PATH % {
447 "version": self.version,
448 "host_arch": prebuilt._HOST_ARCH,
449 "target": target,
450 }
451 packages_url_suffix = "%s/packages" % url_suffix.rstrip("/")
452 url_value = "%s/%s/" % (
453 self.binhost.rstrip("/"),
454 packages_url_suffix.rstrip("/"),
455 )
456 urls = [url_value.replace("foo", "bar"), url_value]
457 binhost = " ".join(urls)
458 uploader = prebuilt.PrebuiltUploader(
459 self.upload_location,
460 "public-read",
461 self.binhost,
462 [],
463 self.build_path,
464 [],
465 False,
466 "foo",
467 False,
468 target,
469 slave_targets,
470 self.version,
Bob Haarmanc0082602022-09-20 16:12:43 -0700471 report,
Alex Klein1699fab2022-09-08 08:46:06 -0600472 chroot=chroot,
473 )
474 uploader.SyncHostPrebuilts(self.key, True, True)
Bob Haarmanc0082602022-09-20 16:12:43 -0700475 self.assertEqual(
476 report,
477 {
478 "created_cls": ["https://crrev.com/unittest/1"],
479 },
480 )
Alex Klein1699fab2022-09-08 08:46:06 -0600481 self.upload_mock.assert_called_once_with(
482 package_path, packages_url_suffix
483 )
484 self.rev_mock.assert_called_once_with(
Bob Haarmanc0082602022-09-20 16:12:43 -0700485 mock.ANY, {self.key: binhost}, report, dryrun=False
Alex Klein1699fab2022-09-08 08:46:06 -0600486 )
487 self.update_binhost_mock.assert_called_once_with(
488 mock.ANY, self.key, binhost
489 )
David James05bcb2b2011-02-09 09:25:47 -0800490
Alex Klein1699fab2022-09-08 08:46:06 -0600491 def testSyncHostPrebuilts(self):
492 self._testSyncHostPrebuilts(chroot=None)
Bob Haarmand1225ea2022-01-19 22:01:42 +0000493
Alex Klein1699fab2022-09-08 08:46:06 -0600494 def testSyncHostPrebuiltsWithChroot(self):
495 self._testSyncHostPrebuilts("/test/chroot")
Bob Haarmand1225ea2022-01-19 22:01:42 +0000496
Alex Klein1699fab2022-09-08 08:46:06 -0600497 def testSyncBoardPrebuilts(self):
498 board = "x86-foo"
499 target = prebuilt.BuildTarget(board, "aura")
500 slave_targets = [prebuilt.BuildTarget("x86-bar", "aura")]
501 board_path = os.path.join(
502 self.build_path, prebuilt._BOARD_PATH % {"board": board}
503 )
504 package_path = os.path.join(board_path, "packages")
505 url_suffix = prebuilt._REL_BOARD_PATH % {
506 "version": self.version,
507 "target": target,
508 }
509 packages_url_suffix = "%s/packages" % url_suffix.rstrip("/")
510 url_value = "%s/%s/" % (
511 self.binhost.rstrip("/"),
512 packages_url_suffix.rstrip("/"),
513 )
514 bar_binhost = url_value.replace("foo", "bar")
515 determine_mock = self.PatchObject(
516 prebuilt, "DeterminePrebuiltConfFile", side_effect=("bar", "foo")
517 )
518 self.PatchObject(prebuilt.PrebuiltUploader, "_UploadSdkTarball")
Bob Haarmanc0082602022-09-20 16:12:43 -0700519 report = {}
Alex Klein1699fab2022-09-08 08:46:06 -0600520 with parallel_unittest.ParallelMock():
521 multiprocessing.Process.exitcode = 0
522 uploader = prebuilt.PrebuiltUploader(
523 self.upload_location,
524 "public-read",
525 self.binhost,
526 [],
527 self.build_path,
528 [],
529 False,
530 "foo",
531 False,
532 target,
533 slave_targets,
534 self.version,
Bob Haarmanc0082602022-09-20 16:12:43 -0700535 report,
Alex Klein1699fab2022-09-08 08:46:06 -0600536 )
537 uploader.SyncBoardPrebuilts(
538 self.key, True, True, True, None, None, None, None, None
539 )
540 determine_mock.assert_has_calls(
541 [
542 mock.call(self.build_path, slave_targets[0]),
543 mock.call(self.build_path, target),
544 ]
545 )
546 self.upload_mock.assert_called_once_with(
547 package_path, packages_url_suffix
548 )
549 self.rev_mock.assert_has_calls(
550 [
Bob Haarmanc0082602022-09-20 16:12:43 -0700551 mock.call(
552 "bar",
553 {self.key: bar_binhost},
554 {
555 "created_cls": [
556 "https://crrev.com/unittest/1",
557 "https://crrev.com/unittest/2",
558 ],
559 },
560 dryrun=False,
561 ),
562 mock.call(
563 "foo",
564 {self.key: url_value},
565 {
566 "created_cls": [
567 "https://crrev.com/unittest/1",
568 "https://crrev.com/unittest/2",
569 ],
570 },
571 dryrun=False,
572 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600573 ]
574 )
575 self.update_binhost_mock.assert_has_calls(
576 [
577 mock.call(mock.ANY, self.key, bar_binhost),
578 mock.call(mock.ANY, self.key, url_value),
579 ]
580 )
David James05bcb2b2011-02-09 09:25:47 -0800581
582
Mike Frysinger36870f92015-04-12 02:59:55 -0400583class TestMain(cros_test_lib.MockTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600584 """Tests for the main() function."""
David Jamesc0f158a2011-02-22 16:07:29 -0800585
Alex Klein1699fab2022-09-08 08:46:06 -0600586 def testMain(self):
587 """Test that the main function works."""
Bob Haarman35460c22022-11-08 00:11:59 +0000588 # Use a real object as returned from ParseOptions as a spec for
589 # the mock options object, so that we don't have any properties
590 # that the real object doesn't have.
591 options_spec, _ = prebuilt.ParseOptions(
592 [
593 "--dry-run",
594 "--build-path",
595 "/trunk",
596 "-u",
597 "gs://upload",
598 ]
599 )
600 options = mock.MagicMock(spec=options_spec)
Alex Klein1699fab2022-09-08 08:46:06 -0600601 old_binhost = "http://prebuilt/1"
602 options.previous_binhost_url = [old_binhost]
603 options.board = "x86-foo"
604 options.profile = None
605 target = prebuilt.BuildTarget(options.board, options.profile)
606 options.build_path = "/trunk"
607 options.chroot = None
608 options.dryrun = False
609 options.private = True
610 options.packages = []
611 options.sync_host = True
612 options.git_sync = True
613 options.upload_board_tarball = True
614 options.prepackaged_tarball = None
615 options.toolchains_overlay_tarballs = []
616 options.toolchains_overlay_upload_path = ""
617 options.toolchain_tarballs = []
618 options.toolchain_upload_path = ""
619 options.upload = "gs://upload/"
620 options.binhost_base_url = options.upload
621 options.prepend_version = True
622 options.set_version = None
623 options.skip_upload = False
624 options.filters = True
625 options.key = "PORTAGE_BINHOST"
626 options.binhost_conf_dir = None
627 options.sync_binhost_conf = True
628 options.slave_targets = [prebuilt.BuildTarget("x86-bar", "aura")]
629 self.PatchObject(
630 prebuilt, "ParseOptions", return_value=tuple([options, target])
631 )
632 self.PatchObject(binpkg, "GrabRemotePackageIndex", return_value=True)
633 init_mock = self.PatchObject(
634 prebuilt.PrebuiltUploader, "__init__", return_value=None
635 )
636 expected_gs_acl_path = os.path.join(
637 "/fake_path", prebuilt._GOOGLESTORAGE_GSUTIL_FILE
638 )
639 self.PatchObject(
640 portage_util, "FindOverlayFile", return_value=expected_gs_acl_path
641 )
642 host_mock = self.PatchObject(
643 prebuilt.PrebuiltUploader, "SyncHostPrebuilts", return_value=None
644 )
645 board_mock = self.PatchObject(
646 prebuilt.PrebuiltUploader, "SyncBoardPrebuilts", return_value=None
647 )
Mike Frysinger36870f92015-04-12 02:59:55 -0400648
Alex Klein1699fab2022-09-08 08:46:06 -0600649 prebuilt.main([])
Mike Frysinger36870f92015-04-12 02:59:55 -0400650
Alex Klein1699fab2022-09-08 08:46:06 -0600651 init_mock.assert_called_once_with(
652 options.upload,
653 expected_gs_acl_path,
654 options.upload,
655 mock.ANY,
656 options.build_path,
657 options.packages,
658 False,
659 None,
660 False,
661 target,
662 options.slave_targets,
663 mock.ANY,
Bob Haarmanc0082602022-09-20 16:12:43 -0700664 {},
Alex Klein1699fab2022-09-08 08:46:06 -0600665 None,
666 )
667 board_mock.assert_called_once_with(
668 options.key,
669 options.git_sync,
670 options.sync_binhost_conf,
671 options.upload_board_tarball,
672 None,
673 [],
674 "",
675 [],
676 "",
677 )
678 host_mock.assert_called_once_with(
679 options.key, options.git_sync, options.sync_binhost_conf
680 )
David Jamesc0f158a2011-02-22 16:07:29 -0800681
Mike Frysinger9e979b92012-11-29 02:55:09 -0500682
Mike Frysinger68182472014-11-05 22:38:39 -0500683class TestSdk(cros_test_lib.MockTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600684 """Test logic related to uploading SDK binaries"""
Mike Frysinger9e979b92012-11-29 02:55:09 -0500685
Alex Klein1699fab2022-09-08 08:46:06 -0600686 def setUp(self):
687 self.PatchObject(
688 prebuilt,
689 "_GsUpload",
690 side_effect=Exception("should not get called"),
691 )
692 self.PatchObject(
693 prebuilt,
694 "UpdateBinhostConfFile",
695 side_effect=Exception("should not get called"),
696 )
697 self.upload_mock = self.PatchObject(
698 prebuilt.PrebuiltUploader, "_Upload"
699 )
Mike Frysinger9e979b92012-11-29 02:55:09 -0500700
Alex Klein1699fab2022-09-08 08:46:06 -0600701 self.acl = "magic-acl"
Mike Frysinger9e979b92012-11-29 02:55:09 -0500702
Alex Klein1699fab2022-09-08 08:46:06 -0600703 # All these args pretty much get ignored. Whee.
704 self.uploader = prebuilt.PrebuiltUploader(
705 "gs://foo",
706 self.acl,
707 "prebuilt",
708 [],
709 "/",
710 [],
711 False,
712 "foo",
713 False,
714 "x86-foo",
715 [],
716 "chroot-1234",
Bob Haarmanc0082602022-09-20 16:12:43 -0700717 report={},
Alex Klein1699fab2022-09-08 08:46:06 -0600718 )
Mike Frysinger9e979b92012-11-29 02:55:09 -0500719
Alex Klein1699fab2022-09-08 08:46:06 -0600720 def testSdkUpload(
721 self,
722 to_tarballs=(),
723 to_upload_path=None,
724 tc_tarballs=(),
725 tc_upload_path=None,
726 ):
727 """Make sure we can upload just an SDK tarball"""
728 tar = "sdk.tar.xz"
729 ver = "1234"
730 vtar = "cros-sdk-%s.tar.xz" % ver
Mike Frysinger9e979b92012-11-29 02:55:09 -0500731
Alex Klein1699fab2022-09-08 08:46:06 -0600732 calls = [
733 mock.call(
734 "%s.Manifest" % tar, "gs://chromiumos-sdk/%s.Manifest" % vtar
735 ),
736 mock.call(tar, "gs://chromiumos-sdk/%s" % vtar),
737 ]
738 for to in to_tarballs:
739 to = to.split(":")
740 calls.append(
741 mock.call(
742 to[1],
743 ("gs://chromiumos-sdk/" + to_upload_path)
744 % {"toolchains": to[0]},
745 )
746 )
747 for tc in tc_tarballs:
748 tc = tc.split(":")
749 calls.append(
750 mock.call(
751 tc[1],
752 ("gs://chromiumos-sdk/" + tc_upload_path)
753 % {"target": tc[0]},
754 )
755 )
756 calls.append(
757 mock.call(mock.ANY, "gs://chromiumos-sdk/cros-sdk-latest.conf")
758 )
Mike Frysinger9e979b92012-11-29 02:55:09 -0500759
Alex Klein1699fab2022-09-08 08:46:06 -0600760 self.uploader._UploadSdkTarball(
761 "amd64-host",
762 "",
763 tar,
764 to_tarballs,
765 to_upload_path,
766 tc_tarballs,
767 tc_upload_path,
768 )
769 self.upload_mock.assert_has_calls(calls)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500770
Alex Klein1699fab2022-09-08 08:46:06 -0600771 def testBoardOverlayTarballUpload(self):
772 """Make sure processing of board-specific overlay tarballs works."""
773 to_tarballs = (
774 (
775 "i686-pc-linux-gnu:"
776 "/some/path/built-sdk-overlay-toolchains-i686-pc-linux-gnu.tar.xz"
777 ),
778 (
779 "armv7a-cros-linux-gnueabi-arm-none-eabi:"
780 "/some/path/built-sdk-overlay-toolchains-armv7a-cros-linux-gnueabi-"
781 "arm-none-eabi"
782 ),
783 )
784 to_upload_path = "1994/04/cros-sdk-overlay-toolchains-%(toolchains)s-1994.04.02.tar.xz"
785 self.testSdkUpload(
786 to_tarballs=to_tarballs, to_upload_path=to_upload_path
787 )
Gilad Arnoldad333182015-05-27 15:50:41 -0700788
Alex Klein1699fab2022-09-08 08:46:06 -0600789 def testToolchainTarballUpload(self):
790 """Make sure processing of toolchain tarballs works."""
791 tc_tarballs = (
792 "i686:/some/i686.tar.xz",
793 "arm-none:/some/arm.tar.xz",
794 )
795 tc_upload_path = "1994/04/%(target)s-1994.04.02.tar.xz"
796 self.testSdkUpload(
797 tc_tarballs=tc_tarballs, tc_upload_path=tc_upload_path
798 )