blob: a37420f367cbadf7196da9a7e913a92582c8ef80 [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2013 The ChromiumOS Authors
Aviv Keshetb1238c32013-04-01 11:42:13 -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 autotest_quickmerge."""
6
Mike Frysinger166fea02021-02-12 05:30:33 -05007from unittest import mock
8
Aviv Keshetb1238c32013-04-01 11:42:13 -07009from chromite.lib import cros_test_lib
10from chromite.scripts import autotest_quickmerge
11
Aviv Keshet787ffcd2013-04-08 15:14:56 -070012
13RSYNC_TEST_OUTPUT = """.d..t...... ./
14>f..t...... touched file with spaces
15>f..t...... touched_file
16>f.st...... modified_contents_file
17.f...p..... modified_permissions_file
18.f....o.... modified_owner_file
19>f+++++++++ new_file
20cL+++++++++ new_symlink -> directory_a/new_file_in_directory
21.d..t...... directory_a/
22>f+++++++++ directory_a/new_file_in_directory
23>f..t...... directory_a/touched_file_in_directory
24cd+++++++++ new_empty_directory/
25.d..t...... touched_empty_directory/"""
26# The output format of rsync's itemized changes has a few unusual cases
27# that are ambiguous. For instance, if the operation involved creating a
28# symbolic link named "a -> b" to a file named "c", the rsync output would be:
29# cL+++++++++ a -> b -> c
30# which is indistinguishable from the output for creating a symbolic link named
31# "a" to a file named "b -> c".
32# Since there is no easy resolution to this ambiguity, and it seems like a case
33# that would rarely or never be encountered in the wild, rsync quickmerge
34# will exclude all files which contain the substring " -> " in their name.
35
Mike Frysingerfcca49e2021-03-17 01:09:20 -040036RSYNC_TEST_OUTPUT_FOR_PACKAGE_UPDATE = """\
37>f..t...... client/ardvark.py
Aviv Keshet75d65962013-04-17 16:15:23 -070038.d..t...... client/site_tests/
39>f+++++++++ client/site_tests/nothing.py
40.d..t...... client/site_tests/factory_Leds/
41>f+++++++++ client/site_tests/factory_Leds/factory_Leds2.py
42>f..tpog... client/site_tests/login_UserPolicyKeys/control
43>f..tpog... client/site_tests/login_UserPolicyKeys/login_UserPolicyKeys.py
44>f..t...... client/site_tests/platform_Cryptohome/platform_Cryptohome.py
45>f..tpog... server/site_tests/security_DbusFuzzServer/control
46>f..t.og... utils/coverage_suite.py
47.d..t...... client/site_tests/power_Thermal/
48cd+++++++++ client/site_tests/power_Thermal/a/
49cd+++++++++ client/site_tests/power_Thermal/a/b/
50cd+++++++++ client/site_tests/power_Thermal/a/b/c/
51>f+++++++++ client/site_tests/power_Thermal/a/b/c/d.py"""
52
Alex Klein1699fab2022-09-08 08:46:06 -060053RSYNC_TEST_DESTINATION_PATH = "/foo/bar/"
Aviv Keshet940c17f2013-04-11 18:41:42 -070054
Alex Klein1699fab2022-09-08 08:46:06 -060055TEST_PACKAGE_CP = "a_cute/little_puppy"
56TEST_PACKAGE_CPV = "a_cute/little_puppy-3.14159"
57TEST_PACKAGE_C = "a_cute"
58TEST_PACKAGE_PV = "little_puppy-3.14159"
59TEST_PORTAGE_ROOT = "/bib/bob/"
Aviv Keshet940c17f2013-04-11 18:41:42 -070060TEST_PACKAGE_OLDCONTENTS = {
Alex Klein1699fab2022-09-08 08:46:06 -060061 "/by/the/prickling/of/my/thumbs": ("obj", "1234", "4321"),
62 "/something/wicked/this/way/comes": ("dir",),
Aviv Keshet940c17f2013-04-11 18:41:42 -070063}
64
Mike Frysingere65f3752014-12-08 00:46:39 -050065
Mike Frysingercc851fc2014-12-08 11:31:59 -050066class ItemizeChangesFromRsyncOutput(cros_test_lib.TestCase):
Alex Klein1699fab2022-09-08 08:46:06 -060067 """Test autotest_quickmerge.ItemizeChangesFromRsyncOutput."""
Aviv Keshet787ffcd2013-04-08 15:14:56 -070068
Alex Klein1699fab2022-09-08 08:46:06 -060069 def testItemizeChangesFromRsyncOutput(self):
70 """Test that rsync output parser returns correct FileMutations."""
71 expected_new = set(
72 [
73 (">f+++++++++", "/foo/bar/new_file"),
74 (">f+++++++++", "/foo/bar/directory_a/new_file_in_directory"),
75 ("cL+++++++++", "/foo/bar/new_symlink"),
76 ]
77 )
Aviv Keshet787ffcd2013-04-08 15:14:56 -070078
Alex Klein1699fab2022-09-08 08:46:06 -060079 expected_mod = set(
80 [
81 (">f..t......", "/foo/bar/touched file with spaces"),
82 (">f..t......", "/foo/bar/touched_file"),
83 (">f.st......", "/foo/bar/modified_contents_file"),
84 (".f...p.....", "/foo/bar/modified_permissions_file"),
85 (".f....o....", "/foo/bar/modified_owner_file"),
86 (
87 ">f..t......",
88 "/foo/bar/directory_a/touched_file_in_directory",
89 ),
90 ]
91 )
Aviv Keshet787ffcd2013-04-08 15:14:56 -070092
Alex Klein1699fab2022-09-08 08:46:06 -060093 expected_dir = set([("cd+++++++++", "/foo/bar/new_empty_directory/")])
Aviv Keshet787ffcd2013-04-08 15:14:56 -070094
Alex Klein1699fab2022-09-08 08:46:06 -060095 report = autotest_quickmerge.ItemizeChangesFromRsyncOutput(
96 RSYNC_TEST_OUTPUT, RSYNC_TEST_DESTINATION_PATH
97 )
Aviv Keshet787ffcd2013-04-08 15:14:56 -070098
Alex Klein1699fab2022-09-08 08:46:06 -060099 self.assertEqual(expected_new, set(report.new_files))
100 self.assertEqual(expected_mod, set(report.modified_files))
101 self.assertEqual(expected_dir, set(report.new_directories))
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700102
103
Mike Frysingercc851fc2014-12-08 11:31:59 -0500104class PackageNameParsingTest(cros_test_lib.TestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600105 """Test autotest_quickmerge.GetStalePackageNames."""
Aviv Keshet75d65962013-04-17 16:15:23 -0700106
Alex Klein1699fab2022-09-08 08:46:06 -0600107 def testGetStalePackageNames(self):
108 autotest_sysroot = "/an/arbitrary/path/"
109 change_report = autotest_quickmerge.ItemizeChangesFromRsyncOutput(
110 RSYNC_TEST_OUTPUT_FOR_PACKAGE_UPDATE, autotest_sysroot
111 )
112 package_matches = autotest_quickmerge.GetStalePackageNames(
113 change_report.modified_files + change_report.new_files,
114 autotest_sysroot,
115 )
116 expected_set = set(
117 [
118 "factory_Leds",
119 "login_UserPolicyKeys",
120 "platform_Cryptohome",
121 "power_Thermal",
122 ]
123 )
124 self.assertEqual(set(package_matches), expected_set)
Aviv Keshet75d65962013-04-17 16:15:23 -0700125
126
Benjamin Gordon121a2aa2018-05-04 16:24:45 -0600127class RsyncCommandTest(cros_test_lib.RunCommandTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600128 """Test autotest_quickmerge.RsyncQuickmerge."""
Aviv Keshetb1238c32013-04-01 11:42:13 -0700129
Alex Klein1699fab2022-09-08 08:46:06 -0600130 def testRsyncQuickmergeCommand(self):
131 """Test that RsyncQuickMerge makes correct call to sudo_run"""
132 include_file_name = "an_include_file_name"
133 source_path = "a_source_path"
134 sysroot_path = "a_sysroot_path"
Aviv Keshetb1238c32013-04-01 11:42:13 -0700135
Alex Klein1699fab2022-09-08 08:46:06 -0600136 expected_command = [
137 "rsync",
138 "-a",
139 "-n",
140 "-u",
141 "-i",
142 "--exclude=**.pyc",
143 "--exclude=**.pyo",
144 "--exclude=** -> *",
145 "--include-from=%s" % include_file_name,
146 "--exclude=*",
147 source_path,
148 sysroot_path,
149 ]
Aviv Keshetb1238c32013-04-01 11:42:13 -0700150
Alex Klein1699fab2022-09-08 08:46:06 -0600151 autotest_quickmerge.RsyncQuickmerge(
152 source_path,
153 sysroot_path,
154 include_file_name,
155 pretend=True,
156 overwrite=False,
157 )
Aviv Keshetb1238c32013-04-01 11:42:13 -0700158
Alex Klein1699fab2022-09-08 08:46:06 -0600159 self.assertCommandContains(expected_command)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700160
161
Mike Frysingerc9785342014-12-08 00:47:08 -0500162class PortageManipulationsTest(cros_test_lib.MockTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600163 """Test usage of autotest_quickmerge.portage."""
Don Garrett25f309a2014-03-19 14:02:12 -0700164
Alex Klein1699fab2022-09-08 08:46:06 -0600165 def testUpdatePackageContents(self):
Alex Klein68b270c2023-04-14 14:42:50 -0600166 """Test UpdatePackageContents makes the correct calls to portage."""
Alex Klein1699fab2022-09-08 08:46:06 -0600167 autotest_quickmerge.portage = mock.MagicMock()
168 portage = autotest_quickmerge.portage
Aviv Keshet940c17f2013-04-11 18:41:42 -0700169
Alex Klein1699fab2022-09-08 08:46:06 -0600170 portage.root = TEST_PORTAGE_ROOT
Aviv Keshet940c17f2013-04-11 18:41:42 -0700171
Alex Klein1699fab2022-09-08 08:46:06 -0600172 mock_vartree = mock.MagicMock()
173 mock_vartree.settings = {"an arbitrary": "dictionary"}
174 mock_tree = {TEST_PORTAGE_ROOT: {"vartree": mock_vartree}}
175 portage.create_trees.return_value = mock_tree
Aviv Keshet940c17f2013-04-11 18:41:42 -0700176
Alex Klein1699fab2022-09-08 08:46:06 -0600177 mock_vartree.dbapi = mock.MagicMock()
178 mock_vartree.dbapi.cp_list.return_value = [TEST_PACKAGE_CPV]
Aviv Keshet940c17f2013-04-11 18:41:42 -0700179
Alex Klein1699fab2022-09-08 08:46:06 -0600180 mock_package = mock.MagicMock()
181 portage.dblink.return_value = mock_package # pylint: disable=no-member
182 mock_package.getcontents.return_value = TEST_PACKAGE_OLDCONTENTS
Aviv Keshet940c17f2013-04-11 18:41:42 -0700183
Alex Klein1699fab2022-09-08 08:46:06 -0600184 EXPECTED_NEW_ENTRIES = {
185 "/foo/bar/new_empty_directory": ("dir",),
186 "/foo/bar/directory_a/new_file_in_directory": ("obj", "0", "0"),
187 "/foo/bar/new_file": ("obj", "0", "0"),
188 "/foo/bar/new_symlink": ("obj", "0", "0"),
189 }
190 RESULT_DICIONARY = TEST_PACKAGE_OLDCONTENTS.copy()
191 RESULT_DICIONARY.update(EXPECTED_NEW_ENTRIES)
Aviv Keshet940c17f2013-04-11 18:41:42 -0700192
Alex Klein1699fab2022-09-08 08:46:06 -0600193 mock_vartree.dbapi.writeContentsToContentsFile(
194 mock_package, RESULT_DICIONARY
195 )
Aviv Keshet940c17f2013-04-11 18:41:42 -0700196
Alex Klein1699fab2022-09-08 08:46:06 -0600197 change_report = autotest_quickmerge.ItemizeChangesFromRsyncOutput(
198 RSYNC_TEST_OUTPUT, RSYNC_TEST_DESTINATION_PATH
199 )
200 autotest_quickmerge.UpdatePackageContents(
201 change_report, TEST_PACKAGE_CP, TEST_PORTAGE_ROOT
202 )
Aviv Keshet940c17f2013-04-11 18:41:42 -0700203
Aviv Keshet940c17f2013-04-11 18:41:42 -0700204
Mike Frysingercc851fc2014-12-08 11:31:59 -0500205class PortageAPITest(cros_test_lib.TestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600206 """Ensures that required portage API exists."""
Mike Frysingere65f3752014-12-08 00:46:39 -0500207
Alex Klein1699fab2022-09-08 08:46:06 -0600208 def runTest(self):
209 try:
210 import portage
211 except ImportError:
212 self.skipTest(
213 "Portage not available in test environment. Re-run test "
214 "in chroot."
215 )
216 try:
217 # pylint: disable=no-member
218 f = portage.vardbapi.writeContentsToContentsFile
219 except AttributeError:
220 self.fail(
221 "Required writeContentsToContentsFile function does "
222 "not exist."
223 )
Aviv Keshet940c17f2013-04-11 18:41:42 -0700224
Alex Klein1699fab2022-09-08 08:46:06 -0600225 self.assertTrue(
226 callable(f),
227 msg="Required writeContentsToContentsFile is not a function.",
228 )