blob: 827869a9eeed4a7aef8f2c969090f06441c7957c [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2015 The ChromiumOS Authors
David Pursell9476bf42015-03-30 13:34:27 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Unit tests for the deploy module."""
6
David Pursell9476bf42015-03-30 13:34:27 -07007import json
Ralph Nathane01ccf12015-04-16 10:40:32 -07008import multiprocessing
David Pursell9476bf42015-03-30 13:34:27 -07009import os
Mike Frysinger050fa5a2019-12-01 16:16:29 -050010import sys
Mike Frysinger166fea02021-02-12 05:30:33 -050011from unittest import mock
David Pursell9476bf42015-03-30 13:34:27 -070012
Ralph Nathane01ccf12015-04-16 10:40:32 -070013from chromite.cli import command
David Pursell9476bf42015-03-30 13:34:27 -070014from chromite.cli import deploy
Mike Frysinger06a51c82021-04-06 11:39:17 -040015from chromite.lib import build_target_lib
David Pursell9476bf42015-03-30 13:34:27 -070016from chromite.lib import cros_build_lib
17from chromite.lib import cros_test_lib
Jae Hoon Kimdf220852023-04-14 19:20:13 +000018from chromite.lib import dlc_lib
Brian Norris2eee8892021-04-06 16:23:23 -070019from chromite.lib import osutils
Ralph Nathane01ccf12015-04-16 10:40:32 -070020from chromite.lib import remote_access
Brian Norris2eee8892021-04-06 16:23:23 -070021from chromite.lib import sysroot_lib
Sloan Johnsona85640f2021-10-01 22:32:40 +000022from chromite.lib import unittest_lib
Alex Klein18a60af2020-06-11 12:08:47 -060023from chromite.lib.parser import package_info
Alex Klein32223fd2023-08-22 11:19:25 -060024from chromite.utils import os_util
Mike Frysinger40ffb532021-02-12 07:36:08 -050025
Greg Edelstona4c9b3b2020-01-07 17:51:13 -070026
Chris McDonald186b9ee2020-04-16 05:56:49 -060027pytestmark = [cros_test_lib.pytestmark_inside_only]
Greg Edelstona4c9b3b2020-01-07 17:51:13 -070028
29
30if cros_build_lib.IsInsideChroot():
Alex Klein1699fab2022-09-08 08:46:06 -060031 import portage # pylint: disable=import-error
David Pursell9476bf42015-03-30 13:34:27 -070032
33
34# pylint: disable=protected-access
35
36
Jae Hoon Kimdf220852023-04-14 19:20:13 +000037# Example DLC LoadPin digests to test with.
38LOADPIN_TRUSTED_VERITY_ROOT_DIGESTS = """# LOADPIN_TRUSTED_VERITY_ROOT_DIGESTS
3975a799de83eee0ef0f028ea94643d1b2021261e77b8f76fee1d5749847fef431
40"""
41
42# An example LoadPin digest.
43DLC_LOADPIN_DIGEST = (
44 "feeddeadc0de0000000000000000000000000000000000000000000000000000"
45)
46
47
Alex Klein074f94f2023-06-22 10:32:06 -060048class ChromiumOSDeviceFake:
Alex Klein1699fab2022-09-08 08:46:06 -060049 """Fake for device."""
Ralph Nathane01ccf12015-04-16 10:40:32 -070050
Alex Klein1699fab2022-09-08 08:46:06 -060051 def __init__(self):
52 self.board = "board"
53 self.hostname = None
54 self.username = None
55 self.port = None
56 self.lsb_release = None
57 self.cmds = []
58 self.work_dir = "/testdir/"
59 self.selinux_available = False
Jae Hoon Kimdf220852023-04-14 19:20:13 +000060 self.copy_store = None
61 self.cat_file_output = ""
Ralph Nathane01ccf12015-04-16 10:40:32 -070062
Alex Klein1699fab2022-09-08 08:46:06 -060063 def MountRootfsReadWrite(self):
64 return True
Ralph Nathane01ccf12015-04-16 10:40:32 -070065
Alex Klein1699fab2022-09-08 08:46:06 -060066 def IsSELinuxAvailable(self):
67 return self.selinux_available
Ben Pastene5f03b052019-08-12 18:03:24 -070068
Alex Klein1699fab2022-09-08 08:46:06 -060069 def IsSELinuxEnforced(self):
70 return True
Ben Pastene5f03b052019-08-12 18:03:24 -070071
Mike Frysinger445f6bf2023-06-27 11:43:33 -040072 def mkdir(self, _path):
73 return None
74
Alex Klein1699fab2022-09-08 08:46:06 -060075 def run(self, cmd, **_kwargs):
76 self.cmds.append(cmd)
Andrewc7e1c6b2020-02-27 16:03:53 -080077
Alex Klein1699fab2022-09-08 08:46:06 -060078 def CopyToDevice(self, _src, _dest, _mode="rsync", **_kwargs):
Jae Hoon Kimdf220852023-04-14 19:20:13 +000079 if os.path.exists(_src):
80 self.copy_store = osutils.ReadFile(_src)
Alex Klein1699fab2022-09-08 08:46:06 -060081 return True
Andrewc7e1c6b2020-02-27 16:03:53 -080082
Jae Hoon Kimdf220852023-04-14 19:20:13 +000083 def CatFile(self, _src):
84 return self.cat_file_output
85
Ralph Nathane01ccf12015-04-16 10:40:32 -070086
Alex Klein074f94f2023-06-22 10:32:06 -060087class ChromiumOSDeviceHandlerFake:
Alex Klein1699fab2022-09-08 08:46:06 -060088 """Fake for chromite.lib.remote_access.ChomiumOSDeviceHandler."""
David Pursell9476bf42015-03-30 13:34:27 -070089
Alex Klein074f94f2023-06-22 10:32:06 -060090 class RemoteAccessFake:
Alex Klein1699fab2022-09-08 08:46:06 -060091 """Fake for chromite.lib.remote_access.RemoteAccess."""
David Pursell9476bf42015-03-30 13:34:27 -070092
Alex Klein1699fab2022-09-08 08:46:06 -060093 def __init__(self):
94 self.remote_sh_output = None
David Pursell9476bf42015-03-30 13:34:27 -070095
Alex Klein1699fab2022-09-08 08:46:06 -060096 def RemoteSh(self, *_args, **_kwargs):
97 return cros_build_lib.CompletedProcess(stdout=self.remote_sh_output)
David Pursell9476bf42015-03-30 13:34:27 -070098
Alex Klein1699fab2022-09-08 08:46:06 -060099 def __init__(self, *_args, **_kwargs):
100 self._agent = self.RemoteAccessFake()
101 self.device = ChromiumOSDeviceFake()
David Pursell67a82762015-04-30 17:26:59 -0700102
Mike Frysingerc0780a62022-08-29 04:41:56 -0400103 @property
104 def agent(self):
Alex Klein1699fab2022-09-08 08:46:06 -0600105 return self._agent
David Pursell9476bf42015-03-30 13:34:27 -0700106
Alex Klein1699fab2022-09-08 08:46:06 -0600107 def __exit__(self, _type, _value, _traceback):
108 pass
Ralph Nathane01ccf12015-04-16 10:40:32 -0700109
Alex Klein1699fab2022-09-08 08:46:06 -0600110 def __enter__(self):
111 return self.device
Ralph Nathane01ccf12015-04-16 10:40:32 -0700112
113
114class BrilloDeployOperationFake(deploy.BrilloDeployOperation):
Alex Klein1699fab2022-09-08 08:46:06 -0600115 """Fake for deploy.BrilloDeployOperation."""
Ralph Nathane01ccf12015-04-16 10:40:32 -0700116
Alex Klein1699fab2022-09-08 08:46:06 -0600117 def __init__(self, emerge, queue):
118 super().__init__(emerge)
119 self._queue = queue
120
121 def ParseOutput(self, output=None):
122 super().ParseOutput(output)
123 self._queue.put("advance")
Ralph Nathane01ccf12015-04-16 10:40:32 -0700124
David Pursell9476bf42015-03-30 13:34:27 -0700125
Alex Klein074f94f2023-06-22 10:32:06 -0600126class DbApiFake:
Alex Klein1699fab2022-09-08 08:46:06 -0600127 """Fake for Portage dbapi."""
David Pursell9476bf42015-03-30 13:34:27 -0700128
Alex Klein1699fab2022-09-08 08:46:06 -0600129 def __init__(self, pkgs):
130 self.pkg_db = {}
Tim Baine4a783b2023-04-21 20:05:51 +0000131 for cpv, slot, rdeps_raw, build_time, use in pkgs:
Alex Klein1699fab2022-09-08 08:46:06 -0600132 self.pkg_db[cpv] = {
133 "SLOT": slot,
134 "RDEPEND": rdeps_raw,
135 "BUILD_TIME": build_time,
Tim Baine4a783b2023-04-21 20:05:51 +0000136 "USE": use,
Alex Klein1699fab2022-09-08 08:46:06 -0600137 }
David Pursell9476bf42015-03-30 13:34:27 -0700138
Alex Klein1699fab2022-09-08 08:46:06 -0600139 def cpv_all(self):
140 return list(self.pkg_db)
David Pursell9476bf42015-03-30 13:34:27 -0700141
Alex Klein1699fab2022-09-08 08:46:06 -0600142 def aux_get(self, cpv, keys):
143 pkg_info = self.pkg_db[cpv]
144 return [pkg_info[key] for key in keys]
David Pursell9476bf42015-03-30 13:34:27 -0700145
146
Alex Klein074f94f2023-06-22 10:32:06 -0600147class PackageScannerFake:
Alex Klein1699fab2022-09-08 08:46:06 -0600148 """Fake for PackageScanner."""
Ralph Nathane01ccf12015-04-16 10:40:32 -0700149
Alex Klein1699fab2022-09-08 08:46:06 -0600150 def __init__(self, packages, pkgs_attrs, packages_cpvs=None):
151 self.pkgs = packages
152 self.cpvs = packages_cpvs or packages
153 self.listed = []
154 self.num_updates = 0
155 self.pkgs_attrs = pkgs_attrs
Tim Baine4a783b2023-04-21 20:05:51 +0000156 self.warnings_shown = False
Ralph Nathane01ccf12015-04-16 10:40:32 -0700157
Alex Klein1699fab2022-09-08 08:46:06 -0600158 def Run(self, _device, _root, _packages, _update, _deep, _deep_rev):
Tim Baine4a783b2023-04-21 20:05:51 +0000159 return (
160 self.cpvs,
161 self.listed,
162 self.num_updates,
163 self.pkgs_attrs,
164 self.warnings_shown,
165 )
Ralph Nathane01ccf12015-04-16 10:40:32 -0700166
167
Alex Klein074f94f2023-06-22 10:32:06 -0600168class PortageTreeFake:
Alex Klein1699fab2022-09-08 08:46:06 -0600169 """Fake for Portage tree."""
David Pursell9476bf42015-03-30 13:34:27 -0700170
Alex Klein1699fab2022-09-08 08:46:06 -0600171 def __init__(self, dbapi):
172 self.dbapi = dbapi
David Pursell9476bf42015-03-30 13:34:27 -0700173
174
Ralph Nathane01ccf12015-04-16 10:40:32 -0700175class TestInstallPackageScanner(cros_test_lib.MockOutputTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600176 """Test the update package scanner."""
David Pursell9476bf42015-03-30 13:34:27 -0700177
Alex Klein1699fab2022-09-08 08:46:06 -0600178 _BOARD = "foo_board"
179 _BUILD_ROOT = "/build/%s" % _BOARD
180 _VARTREE = [
Tim Baine4a783b2023-04-21 20:05:51 +0000181 (
182 "foo/app1-1.2.3-r4",
183 "0",
184 "foo/app2 !foo/app3",
185 "1413309336",
186 "cros-debug",
187 ),
188 ("foo/app2-4.5.6-r7", "0", "", "1413309336", "cros-debug"),
189 (
190 "foo/app4-2.0.0-r1",
191 "0",
192 "foo/app1 foo/app5",
193 "1413309336",
194 "cros-debug",
195 ),
196 ("foo/app5-3.0.7-r3", "0", "", "1413309336", "cros-debug"),
Alex Klein1699fab2022-09-08 08:46:06 -0600197 ]
David Pursell9476bf42015-03-30 13:34:27 -0700198
Alex Klein1699fab2022-09-08 08:46:06 -0600199 def setUp(self):
200 """Patch imported modules."""
201 self.PatchObject(cros_build_lib, "GetChoice", return_value=0)
202 self.device = ChromiumOSDeviceHandlerFake()
203 self.scanner = deploy._InstallPackageScanner(self._BUILD_ROOT)
204 self.PatchObject(deploy, "_GetDLCInfo", return_value=(None, None))
Tim Baine4a783b2023-04-21 20:05:51 +0000205 self.PatchObject(
206 deploy, "_ConfirmUpdateDespiteWarnings", return_value=True
207 )
David Pursell9476bf42015-03-30 13:34:27 -0700208
Alex Klein1699fab2022-09-08 08:46:06 -0600209 def SetupVartree(self, vartree_pkgs):
Jack Rosenthal2aff1af2023-07-13 18:34:28 -0600210 self.PatchObject(
211 self.scanner,
212 "_get_portage_interpreter",
213 return_value="FAKE_PYTHON",
214 )
Mike Frysingerc0780a62022-08-29 04:41:56 -0400215 self.device.agent.remote_sh_output = json.dumps(vartree_pkgs)
David Pursell9476bf42015-03-30 13:34:27 -0700216
Alex Klein1699fab2022-09-08 08:46:06 -0600217 def SetupBintree(self, bintree_pkgs):
218 bintree = PortageTreeFake(DbApiFake(bintree_pkgs))
219 build_root = os.path.join(self._BUILD_ROOT, "")
220 portage_db = {build_root: {"bintree": bintree}}
221 self.PatchObject(portage, "create_trees", return_value=portage_db)
David Pursell9476bf42015-03-30 13:34:27 -0700222
Alex Klein1699fab2022-09-08 08:46:06 -0600223 def ValidatePkgs(self, actual, expected, constraints=None):
224 # Containing exactly the same packages.
225 self.assertEqual(sorted(expected), sorted(actual))
226 # Packages appear in the right order.
227 if constraints is not None:
228 for needs, needed in constraints:
229 self.assertGreater(actual.index(needs), actual.index(needed))
David Pursell9476bf42015-03-30 13:34:27 -0700230
Alex Klein1699fab2022-09-08 08:46:06 -0600231 def testRunUpdatedVersion(self):
232 self.SetupVartree(self._VARTREE)
233 app1 = "foo/app1-1.2.5-r4"
234 self.SetupBintree(
235 [
Tim Baine4a783b2023-04-21 20:05:51 +0000236 (app1, "0", "foo/app2 !foo/app3", "1413309336", "cros-debug"),
237 ("foo/app2-4.5.6-r7", "0", "", "1413309336", "cros-debug"),
Alex Klein1699fab2022-09-08 08:46:06 -0600238 ]
239 )
Tim Baine4a783b2023-04-21 20:05:51 +0000240 installs, listed, num_updates, _, _ = self.scanner.Run(
Alex Klein1699fab2022-09-08 08:46:06 -0600241 self.device, "/", ["app1"], True, True, True
242 )
243 self.ValidatePkgs(installs, [app1])
244 self.ValidatePkgs(listed, [app1])
245 self.assertEqual(num_updates, 1)
David Pursell9476bf42015-03-30 13:34:27 -0700246
Tim Baine4a783b2023-04-21 20:05:51 +0000247 def testRunUpdatedVersionWithUseMismatch(self):
248 self.SetupVartree(self._VARTREE)
249 app1 = "foo/app1-1.2.5-r4"
250 # Setup the bintree with packages that don't have USE=cros-debug.
251 self.SetupBintree(
252 [
253 (app1, "0", "foo/app2 !foo/app3", "1413309336", ""),
254 ("foo/app2-4.5.6-r7", "0", "", "1413309336", ""),
255 ]
256 )
257 with self.assertLogs(level="WARN") as cm:
258 installs, listed, num_updates, _, _ = self.scanner.Run(
259 self.device, "/", ["app1"], True, True, True
260 )
261 self.ValidatePkgs(installs, [app1])
262 self.ValidatePkgs(listed, [app1])
263 self.assertEqual(num_updates, 1)
264 testline = "USE flags for package foo/app1 do not match"
265 matching_logs = [
266 logline for logline in cm.output if testline in logline
267 ]
268 self.assertTrue(
269 matching_logs, "Failed to detect USE flag mismatch."
270 )
271
Alex Klein1699fab2022-09-08 08:46:06 -0600272 def testRunUpdatedBuildTime(self):
273 self.SetupVartree(self._VARTREE)
274 app1 = "foo/app1-1.2.3-r4"
275 self.SetupBintree(
276 [
Tim Baine4a783b2023-04-21 20:05:51 +0000277 (app1, "0", "foo/app2 !foo/app3", "1413309350", "cros-debug"),
278 ("foo/app2-4.5.6-r7", "0", "", "1413309336", "cros-debug"),
Alex Klein1699fab2022-09-08 08:46:06 -0600279 ]
280 )
Tim Baine4a783b2023-04-21 20:05:51 +0000281 installs, listed, num_updates, _, _ = self.scanner.Run(
Alex Klein1699fab2022-09-08 08:46:06 -0600282 self.device, "/", ["app1"], True, True, True
283 )
284 self.ValidatePkgs(installs, [app1])
285 self.ValidatePkgs(listed, [app1])
286 self.assertEqual(num_updates, 1)
David Pursell9476bf42015-03-30 13:34:27 -0700287
Alex Klein1699fab2022-09-08 08:46:06 -0600288 def testRunExistingDepUpdated(self):
289 self.SetupVartree(self._VARTREE)
290 app1 = "foo/app1-1.2.5-r2"
291 app2 = "foo/app2-4.5.8-r3"
292 self.SetupBintree(
293 [
Tim Baine4a783b2023-04-21 20:05:51 +0000294 (app1, "0", "foo/app2 !foo/app3", "1413309350", "cros-debug"),
295 (app2, "0", "", "1413309350", "cros-debug"),
Alex Klein1699fab2022-09-08 08:46:06 -0600296 ]
297 )
Tim Baine4a783b2023-04-21 20:05:51 +0000298 installs, listed, num_updates, _, _ = self.scanner.Run(
Alex Klein1699fab2022-09-08 08:46:06 -0600299 self.device, "/", ["app1"], True, True, True
300 )
301 self.ValidatePkgs(installs, [app1, app2], constraints=[(app1, app2)])
302 self.ValidatePkgs(listed, [app1])
303 self.assertEqual(num_updates, 2)
David Pursell9476bf42015-03-30 13:34:27 -0700304
Alex Klein1699fab2022-09-08 08:46:06 -0600305 def testRunMissingDepUpdated(self):
306 self.SetupVartree(self._VARTREE)
307 app1 = "foo/app1-1.2.5-r2"
308 app6 = "foo/app6-1.0.0-r1"
309 self.SetupBintree(
310 [
Tim Baine4a783b2023-04-21 20:05:51 +0000311 (
312 app1,
313 "0",
314 "foo/app2 !foo/app3 foo/app6",
315 "1413309350",
316 "cros-debug",
317 ),
318 ("foo/app2-4.5.6-r7", "0", "", "1413309336", "cros-debug"),
319 (app6, "0", "", "1413309350", "cros-debug"),
Alex Klein1699fab2022-09-08 08:46:06 -0600320 ]
321 )
Tim Baine4a783b2023-04-21 20:05:51 +0000322 installs, listed, num_updates, _, _ = self.scanner.Run(
Alex Klein1699fab2022-09-08 08:46:06 -0600323 self.device, "/", ["app1"], True, True, True
324 )
325 self.ValidatePkgs(installs, [app1, app6], constraints=[(app1, app6)])
326 self.ValidatePkgs(listed, [app1])
327 self.assertEqual(num_updates, 1)
David Pursell9476bf42015-03-30 13:34:27 -0700328
Alex Klein1699fab2022-09-08 08:46:06 -0600329 def testRunExistingRevDepUpdated(self):
330 self.SetupVartree(self._VARTREE)
331 app1 = "foo/app1-1.2.5-r2"
332 app4 = "foo/app4-2.0.1-r3"
333 self.SetupBintree(
334 [
Tim Baine4a783b2023-04-21 20:05:51 +0000335 (app1, "0", "foo/app2 !foo/app3", "1413309350", "cros-debug"),
336 (app4, "0", "foo/app1 foo/app5", "1413309350", "cros-debug"),
337 ("foo/app5-3.0.7-r3", "0", "", "1413309336", "cros-debug"),
Alex Klein1699fab2022-09-08 08:46:06 -0600338 ]
339 )
Tim Baine4a783b2023-04-21 20:05:51 +0000340 installs, listed, num_updates, _, _ = self.scanner.Run(
Alex Klein1699fab2022-09-08 08:46:06 -0600341 self.device, "/", ["app1"], True, True, True
342 )
343 self.ValidatePkgs(installs, [app1, app4], constraints=[(app4, app1)])
344 self.ValidatePkgs(listed, [app1])
345 self.assertEqual(num_updates, 2)
David Pursell9476bf42015-03-30 13:34:27 -0700346
Alex Klein1699fab2022-09-08 08:46:06 -0600347 def testRunMissingRevDepNotUpdated(self):
348 self.SetupVartree(self._VARTREE)
349 app1 = "foo/app1-1.2.5-r2"
350 app6 = "foo/app6-1.0.0-r1"
351 self.SetupBintree(
352 [
Tim Baine4a783b2023-04-21 20:05:51 +0000353 (app1, "0", "foo/app2 !foo/app3", "1413309350", "cros-debug"),
354 (app6, "0", "foo/app1", "1413309350", "cros-debug"),
Alex Klein1699fab2022-09-08 08:46:06 -0600355 ]
356 )
Tim Baine4a783b2023-04-21 20:05:51 +0000357 installs, listed, num_updates, _, _ = self.scanner.Run(
Alex Klein1699fab2022-09-08 08:46:06 -0600358 self.device, "/", ["app1"], True, True, True
359 )
360 self.ValidatePkgs(installs, [app1])
361 self.ValidatePkgs(listed, [app1])
362 self.assertEqual(num_updates, 1)
David Pursell9476bf42015-03-30 13:34:27 -0700363
Alex Klein1699fab2022-09-08 08:46:06 -0600364 def testRunTransitiveDepsUpdated(self):
365 self.SetupVartree(self._VARTREE)
366 app1 = "foo/app1-1.2.5-r2"
367 app2 = "foo/app2-4.5.8-r3"
368 app4 = "foo/app4-2.0.0-r1"
369 app5 = "foo/app5-3.0.8-r2"
370 self.SetupBintree(
371 [
Tim Baine4a783b2023-04-21 20:05:51 +0000372 (app1, "0", "foo/app2 !foo/app3", "1413309350", "cros-debug"),
373 (app2, "0", "", "1413309350", "cros-debug"),
374 (app4, "0", "foo/app1 foo/app5", "1413309350", "cros-debug"),
375 (app5, "0", "", "1413309350", "cros-debug"),
Alex Klein1699fab2022-09-08 08:46:06 -0600376 ]
377 )
Tim Baine4a783b2023-04-21 20:05:51 +0000378 installs, listed, num_updates, _, _ = self.scanner.Run(
Alex Klein1699fab2022-09-08 08:46:06 -0600379 self.device, "/", ["app1"], True, True, True
380 )
381 self.ValidatePkgs(
382 installs,
383 [app1, app2, app4, app5],
384 constraints=[(app1, app2), (app4, app1), (app4, app5)],
385 )
386 self.ValidatePkgs(listed, [app1])
387 self.assertEqual(num_updates, 4)
David Pursell9476bf42015-03-30 13:34:27 -0700388
Alex Klein1699fab2022-09-08 08:46:06 -0600389 def testRunDisjunctiveDepsExistingUpdated(self):
390 self.SetupVartree(self._VARTREE)
391 app1 = "foo/app1-1.2.5-r2"
392 self.SetupBintree(
393 [
Tim Baine4a783b2023-04-21 20:05:51 +0000394 (
395 app1,
396 "0",
397 "|| ( foo/app6 foo/app2 ) !foo/app3",
398 "1413309350",
399 "cros-debug",
400 ),
401 ("foo/app2-4.5.6-r7", "0", "", "1413309336", "cros-debug"),
Alex Klein1699fab2022-09-08 08:46:06 -0600402 ]
403 )
Tim Baine4a783b2023-04-21 20:05:51 +0000404 installs, listed, num_updates, _, _ = self.scanner.Run(
Alex Klein1699fab2022-09-08 08:46:06 -0600405 self.device, "/", ["app1"], True, True, True
406 )
407 self.ValidatePkgs(installs, [app1])
408 self.ValidatePkgs(listed, [app1])
409 self.assertEqual(num_updates, 1)
410
411 def testRunDisjunctiveDepsDefaultUpdated(self):
412 self.SetupVartree(self._VARTREE)
413 app1 = "foo/app1-1.2.5-r2"
414 app7 = "foo/app7-1.0.0-r1"
415 self.SetupBintree(
416 [
Tim Baine4a783b2023-04-21 20:05:51 +0000417 (
418 app1,
419 "0",
420 "|| ( foo/app6 foo/app7 ) !foo/app3",
421 "1413309350",
422 "cros-debug",
423 ),
424 (app7, "0", "", "1413309350", "cros-debug"),
Alex Klein1699fab2022-09-08 08:46:06 -0600425 ]
426 )
Tim Baine4a783b2023-04-21 20:05:51 +0000427 installs, listed, num_updates, _, _ = self.scanner.Run(
Alex Klein1699fab2022-09-08 08:46:06 -0600428 self.device, "/", ["app1"], True, True, True
429 )
430 self.ValidatePkgs(installs, [app1, app7], constraints=[(app1, app7)])
431 self.ValidatePkgs(listed, [app1])
432 self.assertEqual(num_updates, 1)
Ralph Nathane01ccf12015-04-16 10:40:32 -0700433
Jack Rosenthal2aff1af2023-07-13 18:34:28 -0600434 def test_get_portage_interpreter(self):
435 """Test getting the portage interpreter from the device."""
436 self.device.agent.remote_sh_output = """\
437/usr/lib/python-exec/python3.6/emerge
438/usr/lib/python-exec/python3.8/emerge
439/usr/lib/python-exec/python3.11/emerge
440"""
441 self.assertEqual(
442 self.scanner._get_portage_interpreter(self.device),
443 "python3.11",
444 )
445
Ralph Nathane01ccf12015-04-16 10:40:32 -0700446
Alex Klein1699fab2022-09-08 08:46:06 -0600447class TestDeploy(
448 cros_test_lib.ProgressBarTestCase, cros_test_lib.MockTempDirTestCase
449):
450 """Test deploy.Deploy."""
Ralph Nathane01ccf12015-04-16 10:40:32 -0700451
Alex Klein1699fab2022-09-08 08:46:06 -0600452 @staticmethod
453 def FakeGetPackagesByCPV(cpvs, _strip, _sysroot):
454 return ["/path/to/%s.tbz2" % cpv.pv for cpv in cpvs]
Gilad Arnold0e1b1da2015-06-10 06:41:05 -0700455
Alex Klein1699fab2022-09-08 08:46:06 -0600456 def setUp(self):
457 # Fake being root to avoid running filesystem commands with sudo_run.
Alex Klein32223fd2023-08-22 11:19:25 -0600458 self.PatchObject(os_util, "is_root_user", return_value=True)
Alex Klein1699fab2022-09-08 08:46:06 -0600459 self._sysroot = os.path.join(self.tempdir, "sysroot")
460 osutils.SafeMakedirs(self._sysroot)
461 self.device = ChromiumOSDeviceHandlerFake()
462 self.PatchObject(
463 remote_access, "ChromiumOSDeviceHandler", return_value=self.device
464 )
465 self.PatchObject(cros_build_lib, "GetBoard", return_value=None)
466 self.PatchObject(
467 build_target_lib,
468 "get_default_sysroot_path",
469 return_value=self._sysroot,
470 )
471 self.package_scanner = self.PatchObject(
472 deploy, "_InstallPackageScanner"
473 )
474 self.get_packages_paths = self.PatchObject(
475 deploy, "_GetPackagesByCPV", side_effect=self.FakeGetPackagesByCPV
476 )
477 self.emerge = self.PatchObject(deploy, "_Emerge", return_value=None)
478 self.unmerge = self.PatchObject(deploy, "_Unmerge", return_value=None)
479 self.PatchObject(deploy, "_GetDLCInfo", return_value=(None, None))
480 # Avoid running the portageq command.
481 sysroot_lib.Sysroot(self._sysroot).WriteConfig(
482 'ARCH="amd64"\nPORTDIR_OVERLAY="%s"' % "/nothing/here"
483 )
484 # make.conf needs to exist to correctly read back config.
485 unittest_lib.create_stub_make_conf(self._sysroot)
Brian Norris2eee8892021-04-06 16:23:23 -0700486
Alex Klein1699fab2022-09-08 08:46:06 -0600487 def testDeployEmerge(self):
488 """Test that deploy._Emerge is called for each package."""
Ralph Nathane01ccf12015-04-16 10:40:32 -0700489
Alex Klein1699fab2022-09-08 08:46:06 -0600490 _BINPKG = "/path/to/bar-1.2.5.tbz2"
Gilad Arnold0e1b1da2015-06-10 06:41:05 -0700491
Alex Klein1699fab2022-09-08 08:46:06 -0600492 def FakeIsFile(fname):
493 return fname == _BINPKG
Gilad Arnold0e1b1da2015-06-10 06:41:05 -0700494
Alex Klein1699fab2022-09-08 08:46:06 -0600495 packages = ["some/foo-1.2.3", _BINPKG, "some/foobar-2.0"]
496 cpvs = ["some/foo-1.2.3", "to/bar-1.2.5", "some/foobar-2.0"]
497 self.package_scanner.return_value = PackageScannerFake(
498 packages,
499 {"some/foo-1.2.3": {}, _BINPKG: {}, "some/foobar-2.0": {}},
500 cpvs,
501 )
502 self.PatchObject(os.path, "isfile", side_effect=FakeIsFile)
Ralph Nathane01ccf12015-04-16 10:40:32 -0700503
Alex Klein1699fab2022-09-08 08:46:06 -0600504 deploy.Deploy(None, ["package"], force=True, clean_binpkg=False)
Ralph Nathane01ccf12015-04-16 10:40:32 -0700505
Alex Klein1699fab2022-09-08 08:46:06 -0600506 # Check that package names were correctly resolved into binary packages.
507 self.get_packages_paths.assert_called_once_with(
508 [package_info.SplitCPV(p) for p in cpvs], True, self._sysroot
509 )
510 # Check that deploy._Emerge is called the right number of times.
511 self.emerge.assert_called_once_with(
512 mock.ANY,
513 [
514 "/path/to/foo-1.2.3.tbz2",
515 "/path/to/bar-1.2.5.tbz2",
516 "/path/to/foobar-2.0.tbz2",
517 ],
518 "/",
519 extra_args=None,
520 )
521 self.assertEqual(self.unmerge.call_count, 0)
Qijiang Fan8a945032019-04-25 20:53:29 +0900522
Alex Klein1699fab2022-09-08 08:46:06 -0600523 def testDeployEmergeDLC(self):
524 """Test that deploy._Emerge installs images for DLC packages."""
525 packages = ["some/foodlc-1.0", "some/bardlc-2.0"]
526 cpvs = ["some/foodlc-1.0", "some/bardlc-2.0"]
527 self.package_scanner.return_value = PackageScannerFake(
528 packages, {"some/foodlc-1.0": {}, "some/bardlc-2.0": {}}, cpvs
529 )
530 self.PatchObject(
531 deploy, "_GetDLCInfo", return_value=("foo_id", "foo_package")
532 )
Xiaochu Liu2726e7c2019-07-18 10:28:10 -0700533
Alex Klein1699fab2022-09-08 08:46:06 -0600534 deploy.Deploy(None, ["package"], force=True, clean_binpkg=False)
535 # Check that dlcservice is restarted (DLC modules are deployed).
536 self.assertTrue(["restart", "dlcservice"] in self.device.device.cmds)
Xiaochu Liu2726e7c2019-07-18 10:28:10 -0700537
Jae Hoon Kimdf220852023-04-14 19:20:13 +0000538 def testDeployDLCLoadPinMissingDeviceDigests(self):
539 """Test that _DeployDLCLoadPin works with missing device digests."""
540 osutils.WriteFile(
541 self.tempdir
542 / dlc_lib.DLC_META_DIR
543 / dlc_lib.DLC_LOADPIN_TRUSTED_VERITY_DIGESTS,
544 LOADPIN_TRUSTED_VERITY_ROOT_DIGESTS,
545 makedirs=True,
546 )
547 with self.device as d:
548 deploy._DeployDLCLoadPin(self.tempdir, d)
549 self.assertEqual(
550 d.copy_store.splitlines()[0], dlc_lib.DLC_LOADPIN_FILE_HEADER
551 )
552 self.assertFalse(DLC_LOADPIN_DIGEST in d.copy_store.splitlines())
553 self.assertTrue(
554 "75a799de83eee0ef0f028ea94643d1b2021261e77b8f76fee1d5749847fef431"
555 in d.copy_store.splitlines()
556 )
557
558 def testDeployDLCLoadPinFeedNewDigests(self):
559 """Test that _DeployDLCLoadPin works with digest format file."""
560 osutils.WriteFile(
561 self.tempdir
562 / dlc_lib.DLC_META_DIR
563 / dlc_lib.DLC_LOADPIN_TRUSTED_VERITY_DIGESTS,
564 LOADPIN_TRUSTED_VERITY_ROOT_DIGESTS,
565 makedirs=True,
566 )
567 with self.device as d:
568 d.cat_file_output = DLC_LOADPIN_DIGEST
569 deploy._DeployDLCLoadPin(self.tempdir, d)
570 self.assertEqual(
571 d.copy_store.splitlines()[0], dlc_lib.DLC_LOADPIN_FILE_HEADER
572 )
573 self.assertTrue(DLC_LOADPIN_DIGEST in d.copy_store.splitlines())
574 self.assertTrue(
575 "75a799de83eee0ef0f028ea94643d1b2021261e77b8f76fee1d5749847fef431"
576 in d.copy_store.splitlines()
577 )
578
Alex Klein1699fab2022-09-08 08:46:06 -0600579 def testDeployEmergeSELinux(self):
580 """Test deploy progress when the device has SELinux"""
Qijiang Fan8a945032019-04-25 20:53:29 +0900581
Alex Klein1699fab2022-09-08 08:46:06 -0600582 _BINPKG = "/path/to/bar-1.2.5.tbz2"
Qijiang Fan8a945032019-04-25 20:53:29 +0900583
Alex Klein1699fab2022-09-08 08:46:06 -0600584 def FakeIsFile(fname):
585 return fname == _BINPKG
Qijiang Fan8a945032019-04-25 20:53:29 +0900586
Alex Klein1699fab2022-09-08 08:46:06 -0600587 def GetRestoreconCommand(pkgfile):
588 remote_path = os.path.join("/testdir/packages/to/", pkgfile)
589 return [
590 [
591 "cd",
592 "/",
593 "&&",
594 "tar",
595 "tf",
596 remote_path,
597 "|",
598 "restorecon",
599 "-i",
600 "-f",
601 "-",
602 ]
603 ]
Qijiang Fan8a945032019-04-25 20:53:29 +0900604
Alex Klein1699fab2022-09-08 08:46:06 -0600605 self.device.device.selinux_available = True
606 packages = ["some/foo-1.2.3", _BINPKG, "some/foobar-2.0"]
607 cpvs = ["some/foo-1.2.3", "to/bar-1.2.5", "some/foobar-2.0"]
608 self.package_scanner.return_value = PackageScannerFake(
609 packages,
610 {"some/foo-1.2.3": {}, _BINPKG: {}, "some/foobar-2.0": {}},
611 cpvs,
612 )
613 self.PatchObject(os.path, "isfile", side_effect=FakeIsFile)
Qijiang Fan8a945032019-04-25 20:53:29 +0900614
Alex Klein1699fab2022-09-08 08:46:06 -0600615 deploy.Deploy(None, ["package"], force=True, clean_binpkg=False)
Qijiang Fan8a945032019-04-25 20:53:29 +0900616
Alex Klein1699fab2022-09-08 08:46:06 -0600617 # Check that package names were correctly resolved into binary packages.
618 self.get_packages_paths.assert_called_once_with(
619 [package_info.SplitCPV(p) for p in cpvs], True, self._sysroot
620 )
621 # Check that deploy._Emerge is called the right number of times.
622 self.assertEqual(self.emerge.call_count, 1)
623 self.assertEqual(self.unmerge.call_count, 0)
Ralph Nathane01ccf12015-04-16 10:40:32 -0700624
Alex Klein1699fab2022-09-08 08:46:06 -0600625 self.assertEqual(
626 self.device.device.cmds,
627 [["setenforce", "0"]]
628 + GetRestoreconCommand("foo-1.2.3.tbz2")
629 + GetRestoreconCommand("bar-1.2.5.tbz2")
630 + GetRestoreconCommand("foobar-2.0.tbz2")
631 + [["setenforce", "1"]],
632 )
Ralph Nathane01ccf12015-04-16 10:40:32 -0700633
Alex Klein1699fab2022-09-08 08:46:06 -0600634 def testDeployUnmerge(self):
635 """Test that deploy._Unmerge is called for each package."""
636 packages = ["foo", "bar", "foobar", "foodlc"]
637 self.package_scanner.return_value = PackageScannerFake(
638 packages,
639 {
640 "foo": {},
641 "bar": {},
642 "foobar": {},
643 "foodlc": {
644 deploy._DLC_ID: "foodlc",
645 deploy._DLC_PACKAGE: "foopackage",
646 },
647 },
648 )
Ralph Nathane01ccf12015-04-16 10:40:32 -0700649
Alex Klein1699fab2022-09-08 08:46:06 -0600650 deploy.Deploy(
651 None, ["package"], force=True, clean_binpkg=False, emerge=False
652 )
Ralph Nathane01ccf12015-04-16 10:40:32 -0700653
Alex Klein1699fab2022-09-08 08:46:06 -0600654 # Check that deploy._Unmerge is called the right number of times.
655 self.assertEqual(self.emerge.call_count, 0)
656 self.unmerge.assert_called_once_with(mock.ANY, packages, "/")
Xiaochu Liu2726e7c2019-07-18 10:28:10 -0700657
Alex Klein1699fab2022-09-08 08:46:06 -0600658 self.assertEqual(
659 self.device.device.cmds,
660 [
661 ["dlcservice_util", "--uninstall", "--id=foodlc"],
662 ["restart", "dlcservice"],
663 ],
664 )
Ralph Nathane01ccf12015-04-16 10:40:32 -0700665
Alex Klein1699fab2022-09-08 08:46:06 -0600666 def testDeployMergeWithProgressBar(self):
667 """Test that BrilloDeployOperation.Run() is called for merge."""
668 packages = ["foo", "bar", "foobar"]
669 self.package_scanner.return_value = PackageScannerFake(
670 packages, {"foo": {}, "bar": {}, "foobar": {}}
671 )
Ralph Nathane01ccf12015-04-16 10:40:32 -0700672
Alex Klein1699fab2022-09-08 08:46:06 -0600673 run = self.PatchObject(
674 deploy.BrilloDeployOperation, "Run", return_value=None
675 )
Ralph Nathane01ccf12015-04-16 10:40:32 -0700676
Alex Klein1699fab2022-09-08 08:46:06 -0600677 self.PatchObject(command, "UseProgressBar", return_value=True)
678 deploy.Deploy(None, ["package"], force=True, clean_binpkg=False)
Ralph Nathane01ccf12015-04-16 10:40:32 -0700679
Alex Klein1699fab2022-09-08 08:46:06 -0600680 # Check that BrilloDeployOperation.Run was called.
681 self.assertTrue(run.called)
Ralph Nathane01ccf12015-04-16 10:40:32 -0700682
Alex Klein1699fab2022-09-08 08:46:06 -0600683 def testDeployUnmergeWithProgressBar(self):
684 """Test that BrilloDeployOperation.Run() is called for unmerge."""
685 packages = ["foo", "bar", "foobar"]
686 self.package_scanner.return_value = PackageScannerFake(
687 packages, {"foo": {}, "bar": {}, "foobar": {}}
688 )
Ralph Nathane01ccf12015-04-16 10:40:32 -0700689
Alex Klein1699fab2022-09-08 08:46:06 -0600690 run = self.PatchObject(
691 deploy.BrilloDeployOperation, "Run", return_value=None
692 )
Ralph Nathane01ccf12015-04-16 10:40:32 -0700693
Alex Klein1699fab2022-09-08 08:46:06 -0600694 self.PatchObject(command, "UseProgressBar", return_value=True)
695 deploy.Deploy(
696 None, ["package"], force=True, clean_binpkg=False, emerge=False
697 )
Ralph Nathane01ccf12015-04-16 10:40:32 -0700698
Alex Klein1699fab2022-09-08 08:46:06 -0600699 # Check that BrilloDeployOperation.Run was called.
700 self.assertTrue(run.called)
Ralph Nathane01ccf12015-04-16 10:40:32 -0700701
Alex Klein1699fab2022-09-08 08:46:06 -0600702 def testBrilloDeployMergeOperation(self):
703 """Test that BrilloDeployOperation works for merge."""
Ralph Nathane01ccf12015-04-16 10:40:32 -0700704
Alex Klein1699fab2022-09-08 08:46:06 -0600705 def func(queue):
706 for event in op.MERGE_EVENTS:
707 queue.get()
708 print(event)
709 sys.stdout.flush()
Ralph Nathane01ccf12015-04-16 10:40:32 -0700710
Alex Klein1699fab2022-09-08 08:46:06 -0600711 queue = multiprocessing.Queue()
712 # Emerge one package.
713 op = BrilloDeployOperationFake(True, queue)
Ralph Nathane01ccf12015-04-16 10:40:32 -0700714
Alex Klein1699fab2022-09-08 08:46:06 -0600715 with self.OutputCapturer():
716 op.Run(func, queue)
Ralph Nathane01ccf12015-04-16 10:40:32 -0700717
Alex Klein1699fab2022-09-08 08:46:06 -0600718 # Check that the progress bar prints correctly.
719 self.AssertProgressBarAllEvents(len(op.MERGE_EVENTS))
Ralph Nathane01ccf12015-04-16 10:40:32 -0700720
Alex Klein1699fab2022-09-08 08:46:06 -0600721 def testBrilloDeployUnmergeOperation(self):
722 """Test that BrilloDeployOperation works for unmerge."""
Ralph Nathane01ccf12015-04-16 10:40:32 -0700723
Alex Klein1699fab2022-09-08 08:46:06 -0600724 def func(queue):
725 for event in op.UNMERGE_EVENTS:
726 queue.get()
727 print(event)
728 sys.stdout.flush()
729
730 queue = multiprocessing.Queue()
731 # Unmerge one package.
732 op = BrilloDeployOperationFake(False, queue)
733
734 with self.OutputCapturer():
735 op.Run(func, queue)
736
737 # Check that the progress bar prints correctly.
738 self.AssertProgressBarAllEvents(len(op.UNMERGE_EVENTS))