Mike Frysinger | f1ba7ad | 2022-09-12 05:42:57 -0400 | [diff] [blame] | 1 | # Copyright 2013 The ChromiumOS Authors |
Aviv Keshet | b1238c3 | 2013-04-01 11:42:13 -0700 | [diff] [blame] | 2 | # 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 Frysinger | 166fea0 | 2021-02-12 05:30:33 -0500 | [diff] [blame] | 7 | from unittest import mock |
| 8 | |
Aviv Keshet | b1238c3 | 2013-04-01 11:42:13 -0700 | [diff] [blame] | 9 | from chromite.lib import cros_test_lib |
| 10 | from chromite.scripts import autotest_quickmerge |
| 11 | |
Aviv Keshet | 787ffcd | 2013-04-08 15:14:56 -0700 | [diff] [blame] | 12 | |
| 13 | RSYNC_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 |
| 20 | cL+++++++++ 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 |
| 24 | cd+++++++++ 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 Frysinger | fcca49e | 2021-03-17 01:09:20 -0400 | [diff] [blame] | 36 | RSYNC_TEST_OUTPUT_FOR_PACKAGE_UPDATE = """\ |
| 37 | >f..t...... client/ardvark.py |
Aviv Keshet | 75d6596 | 2013-04-17 16:15:23 -0700 | [diff] [blame] | 38 | .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/ |
| 48 | cd+++++++++ client/site_tests/power_Thermal/a/ |
| 49 | cd+++++++++ client/site_tests/power_Thermal/a/b/ |
| 50 | cd+++++++++ client/site_tests/power_Thermal/a/b/c/ |
| 51 | >f+++++++++ client/site_tests/power_Thermal/a/b/c/d.py""" |
| 52 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 53 | RSYNC_TEST_DESTINATION_PATH = "/foo/bar/" |
Aviv Keshet | 940c17f | 2013-04-11 18:41:42 -0700 | [diff] [blame] | 54 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 55 | TEST_PACKAGE_CP = "a_cute/little_puppy" |
| 56 | TEST_PACKAGE_CPV = "a_cute/little_puppy-3.14159" |
| 57 | TEST_PACKAGE_C = "a_cute" |
| 58 | TEST_PACKAGE_PV = "little_puppy-3.14159" |
| 59 | TEST_PORTAGE_ROOT = "/bib/bob/" |
Aviv Keshet | 940c17f | 2013-04-11 18:41:42 -0700 | [diff] [blame] | 60 | TEST_PACKAGE_OLDCONTENTS = { |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 61 | "/by/the/prickling/of/my/thumbs": ("obj", "1234", "4321"), |
| 62 | "/something/wicked/this/way/comes": ("dir",), |
Aviv Keshet | 940c17f | 2013-04-11 18:41:42 -0700 | [diff] [blame] | 63 | } |
| 64 | |
Mike Frysinger | e65f375 | 2014-12-08 00:46:39 -0500 | [diff] [blame] | 65 | |
Mike Frysinger | cc851fc | 2014-12-08 11:31:59 -0500 | [diff] [blame] | 66 | class ItemizeChangesFromRsyncOutput(cros_test_lib.TestCase): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 67 | """Test autotest_quickmerge.ItemizeChangesFromRsyncOutput.""" |
Aviv Keshet | 787ffcd | 2013-04-08 15:14:56 -0700 | [diff] [blame] | 68 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 69 | 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 Keshet | 787ffcd | 2013-04-08 15:14:56 -0700 | [diff] [blame] | 78 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 79 | 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 Keshet | 787ffcd | 2013-04-08 15:14:56 -0700 | [diff] [blame] | 92 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 93 | expected_dir = set([("cd+++++++++", "/foo/bar/new_empty_directory/")]) |
Aviv Keshet | 787ffcd | 2013-04-08 15:14:56 -0700 | [diff] [blame] | 94 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 95 | report = autotest_quickmerge.ItemizeChangesFromRsyncOutput( |
| 96 | RSYNC_TEST_OUTPUT, RSYNC_TEST_DESTINATION_PATH |
| 97 | ) |
Aviv Keshet | 787ffcd | 2013-04-08 15:14:56 -0700 | [diff] [blame] | 98 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 99 | 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 Keshet | 787ffcd | 2013-04-08 15:14:56 -0700 | [diff] [blame] | 102 | |
| 103 | |
Mike Frysinger | cc851fc | 2014-12-08 11:31:59 -0500 | [diff] [blame] | 104 | class PackageNameParsingTest(cros_test_lib.TestCase): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 105 | """Test autotest_quickmerge.GetStalePackageNames.""" |
Aviv Keshet | 75d6596 | 2013-04-17 16:15:23 -0700 | [diff] [blame] | 106 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 107 | 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 Keshet | 75d6596 | 2013-04-17 16:15:23 -0700 | [diff] [blame] | 125 | |
| 126 | |
Benjamin Gordon | 121a2aa | 2018-05-04 16:24:45 -0600 | [diff] [blame] | 127 | class RsyncCommandTest(cros_test_lib.RunCommandTestCase): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 128 | """Test autotest_quickmerge.RsyncQuickmerge.""" |
Aviv Keshet | b1238c3 | 2013-04-01 11:42:13 -0700 | [diff] [blame] | 129 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 130 | 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 Keshet | b1238c3 | 2013-04-01 11:42:13 -0700 | [diff] [blame] | 135 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 136 | 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 Keshet | b1238c3 | 2013-04-01 11:42:13 -0700 | [diff] [blame] | 150 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 151 | autotest_quickmerge.RsyncQuickmerge( |
| 152 | source_path, |
| 153 | sysroot_path, |
| 154 | include_file_name, |
| 155 | pretend=True, |
| 156 | overwrite=False, |
| 157 | ) |
Aviv Keshet | b1238c3 | 2013-04-01 11:42:13 -0700 | [diff] [blame] | 158 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 159 | self.assertCommandContains(expected_command) |
Aviv Keshet | b1238c3 | 2013-04-01 11:42:13 -0700 | [diff] [blame] | 160 | |
| 161 | |
Mike Frysinger | c978534 | 2014-12-08 00:47:08 -0500 | [diff] [blame] | 162 | class PortageManipulationsTest(cros_test_lib.MockTestCase): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 163 | """Test usage of autotest_quickmerge.portage.""" |
Don Garrett | 25f309a | 2014-03-19 14:02:12 -0700 | [diff] [blame] | 164 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 165 | def testUpdatePackageContents(self): |
Alex Klein | 68b270c | 2023-04-14 14:42:50 -0600 | [diff] [blame^] | 166 | """Test UpdatePackageContents makes the correct calls to portage.""" |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 167 | autotest_quickmerge.portage = mock.MagicMock() |
| 168 | portage = autotest_quickmerge.portage |
Aviv Keshet | 940c17f | 2013-04-11 18:41:42 -0700 | [diff] [blame] | 169 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 170 | portage.root = TEST_PORTAGE_ROOT |
Aviv Keshet | 940c17f | 2013-04-11 18:41:42 -0700 | [diff] [blame] | 171 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 172 | 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 Keshet | 940c17f | 2013-04-11 18:41:42 -0700 | [diff] [blame] | 176 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 177 | mock_vartree.dbapi = mock.MagicMock() |
| 178 | mock_vartree.dbapi.cp_list.return_value = [TEST_PACKAGE_CPV] |
Aviv Keshet | 940c17f | 2013-04-11 18:41:42 -0700 | [diff] [blame] | 179 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 180 | 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 Keshet | 940c17f | 2013-04-11 18:41:42 -0700 | [diff] [blame] | 183 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 184 | 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 Keshet | 940c17f | 2013-04-11 18:41:42 -0700 | [diff] [blame] | 192 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 193 | mock_vartree.dbapi.writeContentsToContentsFile( |
| 194 | mock_package, RESULT_DICIONARY |
| 195 | ) |
Aviv Keshet | 940c17f | 2013-04-11 18:41:42 -0700 | [diff] [blame] | 196 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 197 | 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 Keshet | 940c17f | 2013-04-11 18:41:42 -0700 | [diff] [blame] | 203 | |
Aviv Keshet | 940c17f | 2013-04-11 18:41:42 -0700 | [diff] [blame] | 204 | |
Mike Frysinger | cc851fc | 2014-12-08 11:31:59 -0500 | [diff] [blame] | 205 | class PortageAPITest(cros_test_lib.TestCase): |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 206 | """Ensures that required portage API exists.""" |
Mike Frysinger | e65f375 | 2014-12-08 00:46:39 -0500 | [diff] [blame] | 207 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 208 | 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 Keshet | 940c17f | 2013-04-11 18:41:42 -0700 | [diff] [blame] | 224 | |
Alex Klein | 1699fab | 2022-09-08 08:46:06 -0600 | [diff] [blame] | 225 | self.assertTrue( |
| 226 | callable(f), |
| 227 | msg="Required writeContentsToContentsFile is not a function.", |
| 228 | ) |