blob: c3d08402b9c286bab6b9f455a5ea151a3b5d2674 [file] [log] [blame]
Aviv Keshetb1238c32013-04-01 11:42:13 -07001# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
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
Aviv Keshetb1238c32013-04-01 11:42:13 -07007from chromite.lib import cros_test_lib
8from chromite.scripts import autotest_quickmerge
Mike Frysinger40ffb532021-02-12 07:36:08 -05009from chromite.third_party import mock
Aviv Keshetb1238c32013-04-01 11:42:13 -070010
Aviv Keshet787ffcd2013-04-08 15:14:56 -070011
12RSYNC_TEST_OUTPUT = """.d..t...... ./
13>f..t...... touched file with spaces
14>f..t...... touched_file
15>f.st...... modified_contents_file
16.f...p..... modified_permissions_file
17.f....o.... modified_owner_file
18>f+++++++++ new_file
19cL+++++++++ new_symlink -> directory_a/new_file_in_directory
20.d..t...... directory_a/
21>f+++++++++ directory_a/new_file_in_directory
22>f..t...... directory_a/touched_file_in_directory
23cd+++++++++ new_empty_directory/
24.d..t...... touched_empty_directory/"""
25# The output format of rsync's itemized changes has a few unusual cases
26# that are ambiguous. For instance, if the operation involved creating a
27# symbolic link named "a -> b" to a file named "c", the rsync output would be:
28# cL+++++++++ a -> b -> c
29# which is indistinguishable from the output for creating a symbolic link named
30# "a" to a file named "b -> c".
31# Since there is no easy resolution to this ambiguity, and it seems like a case
32# that would rarely or never be encountered in the wild, rsync quickmerge
33# will exclude all files which contain the substring " -> " in their name.
34
Mike Frysingerfcca49e2021-03-17 01:09:20 -040035RSYNC_TEST_OUTPUT_FOR_PACKAGE_UPDATE = """\
36>f..t...... client/ardvark.py
Aviv Keshet75d65962013-04-17 16:15:23 -070037.d..t...... client/site_tests/
38>f+++++++++ client/site_tests/nothing.py
39.d..t...... client/site_tests/factory_Leds/
40>f+++++++++ client/site_tests/factory_Leds/factory_Leds2.py
41>f..tpog... client/site_tests/login_UserPolicyKeys/control
42>f..tpog... client/site_tests/login_UserPolicyKeys/login_UserPolicyKeys.py
43>f..t...... client/site_tests/platform_Cryptohome/platform_Cryptohome.py
44>f..tpog... server/site_tests/security_DbusFuzzServer/control
45>f..t.og... utils/coverage_suite.py
46.d..t...... client/site_tests/power_Thermal/
47cd+++++++++ client/site_tests/power_Thermal/a/
48cd+++++++++ client/site_tests/power_Thermal/a/b/
49cd+++++++++ client/site_tests/power_Thermal/a/b/c/
50>f+++++++++ client/site_tests/power_Thermal/a/b/c/d.py"""
51
Aviv Keshet940c17f2013-04-11 18:41:42 -070052RSYNC_TEST_DESTINATION_PATH = '/foo/bar/'
53
54TEST_PACKAGE_CP = 'a_cute/little_puppy'
55TEST_PACKAGE_CPV = 'a_cute/little_puppy-3.14159'
56TEST_PACKAGE_C = 'a_cute'
57TEST_PACKAGE_PV = 'little_puppy-3.14159'
58TEST_PORTAGE_ROOT = '/bib/bob/'
59TEST_PACKAGE_OLDCONTENTS = {
Mike Frysingere65f3752014-12-08 00:46:39 -050060 u'/by/the/prickling/of/my/thumbs': (u'obj', '1234', '4321'),
61 u'/something/wicked/this/way/comes': (u'dir',)
Aviv Keshet940c17f2013-04-11 18:41:42 -070062}
63
Mike Frysingere65f3752014-12-08 00:46:39 -050064
Mike Frysingercc851fc2014-12-08 11:31:59 -050065class ItemizeChangesFromRsyncOutput(cros_test_lib.TestCase):
Don Garrett25f309a2014-03-19 14:02:12 -070066 """Test autotest_quickmerge.ItemizeChangesFromRsyncOutput."""
Aviv Keshet787ffcd2013-04-08 15:14:56 -070067
68 def testItemizeChangesFromRsyncOutput(self):
69 """Test that rsync output parser returns correct FileMutations."""
Aviv Keshet787ffcd2013-04-08 15:14:56 -070070 expected_new = set(
71 [('>f+++++++++', '/foo/bar/new_file'),
72 ('>f+++++++++', '/foo/bar/directory_a/new_file_in_directory'),
73 ('cL+++++++++', '/foo/bar/new_symlink')])
74
75 expected_mod = set(
76 [('>f..t......', '/foo/bar/touched file with spaces'),
77 ('>f..t......', '/foo/bar/touched_file'),
78 ('>f.st......', '/foo/bar/modified_contents_file'),
79 ('.f...p.....', '/foo/bar/modified_permissions_file'),
80 ('.f....o....', '/foo/bar/modified_owner_file'),
81 ('>f..t......', '/foo/bar/directory_a/touched_file_in_directory')])
82
83 expected_dir = set([('cd+++++++++', '/foo/bar/new_empty_directory/')])
84
85 report = autotest_quickmerge.ItemizeChangesFromRsyncOutput(
Aviv Keshet940c17f2013-04-11 18:41:42 -070086 RSYNC_TEST_OUTPUT, RSYNC_TEST_DESTINATION_PATH)
Aviv Keshet787ffcd2013-04-08 15:14:56 -070087
88 self.assertEqual(expected_new, set(report.new_files))
89 self.assertEqual(expected_mod, set(report.modified_files))
90 self.assertEqual(expected_dir, set(report.new_directories))
91
92
Mike Frysingercc851fc2014-12-08 11:31:59 -050093class PackageNameParsingTest(cros_test_lib.TestCase):
Don Garrett25f309a2014-03-19 14:02:12 -070094 """Test autotest_quickmerge.GetStalePackageNames."""
Aviv Keshet75d65962013-04-17 16:15:23 -070095
96 def testGetStalePackageNames(self):
97 autotest_sysroot = '/an/arbitrary/path/'
98 change_report = autotest_quickmerge.ItemizeChangesFromRsyncOutput(
99 RSYNC_TEST_OUTPUT_FOR_PACKAGE_UPDATE, autotest_sysroot)
100 package_matches = autotest_quickmerge.GetStalePackageNames(
101 change_report.modified_files + change_report.new_files,
102 autotest_sysroot)
103 expected_set = set(['factory_Leds', 'login_UserPolicyKeys',
104 'platform_Cryptohome', 'power_Thermal'])
105 self.assertEqual(set(package_matches), expected_set)
106
107
Benjamin Gordon121a2aa2018-05-04 16:24:45 -0600108class RsyncCommandTest(cros_test_lib.RunCommandTestCase):
Don Garrett25f309a2014-03-19 14:02:12 -0700109 """Test autotest_quickmerge.RsyncQuickmerge."""
Aviv Keshetb1238c32013-04-01 11:42:13 -0700110
111 def testRsyncQuickmergeCommand(self):
Mike Frysinger45602c72019-09-22 02:15:11 -0400112 """Test that RsyncQuickMerge makes correct call to sudo_run"""
Aviv Keshetb1238c32013-04-01 11:42:13 -0700113 include_file_name = 'an_include_file_name'
114 source_path = 'a_source_path'
115 sysroot_path = 'a_sysroot_path'
116
117 expected_command = ['rsync', '-a', '-n', '-u', '-i',
118 '--exclude=**.pyc', '--exclude=**.pyo',
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700119 '--exclude=** -> *',
Aviv Keshetb1238c32013-04-01 11:42:13 -0700120 '--include-from=%s' % include_file_name,
121 '--exclude=*',
122 source_path,
123 sysroot_path]
124
125 autotest_quickmerge.RsyncQuickmerge(source_path, sysroot_path,
126 include_file_name,
127 pretend=True,
Aviv Keshet60968ec2013-04-11 18:44:14 -0700128 overwrite=False)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700129
130 self.assertCommandContains(expected_command)
131
132
Mike Frysingerc9785342014-12-08 00:47:08 -0500133class PortageManipulationsTest(cros_test_lib.MockTestCase):
Don Garrett25f309a2014-03-19 14:02:12 -0700134 """Test usage of autotest_quickmerge.portage."""
135
Aviv Keshet940c17f2013-04-11 18:41:42 -0700136 def testUpdatePackageContents(self):
137 """Test that UpdatePackageContents makes the correct calls to portage."""
Mike Frysingerc9785342014-12-08 00:47:08 -0500138 autotest_quickmerge.portage = mock.MagicMock()
Aviv Keshet940c17f2013-04-11 18:41:42 -0700139 portage = autotest_quickmerge.portage
140
141 portage.root = TEST_PORTAGE_ROOT
142
Mike Frysingerc9785342014-12-08 00:47:08 -0500143 mock_vartree = mock.MagicMock()
Aviv Keshet940c17f2013-04-11 18:41:42 -0700144 mock_vartree.settings = {'an arbitrary' : 'dictionary'}
145 mock_tree = {TEST_PORTAGE_ROOT : {'vartree' : mock_vartree}}
Mike Frysingerc9785342014-12-08 00:47:08 -0500146 portage.create_trees.return_value = mock_tree
Aviv Keshet940c17f2013-04-11 18:41:42 -0700147
Mike Frysingerc9785342014-12-08 00:47:08 -0500148 mock_vartree.dbapi = mock.MagicMock()
149 mock_vartree.dbapi.cp_list.return_value = [TEST_PACKAGE_CPV]
Aviv Keshet940c17f2013-04-11 18:41:42 -0700150
Mike Frysingerc9785342014-12-08 00:47:08 -0500151 mock_package = mock.MagicMock()
152 portage.dblink.return_value = mock_package # pylint: disable=no-member
153 mock_package.getcontents.return_value = TEST_PACKAGE_OLDCONTENTS
Aviv Keshet940c17f2013-04-11 18:41:42 -0700154
155 EXPECTED_NEW_ENTRIES = {
156 '/foo/bar/new_empty_directory': (u'dir',),
157 '/foo/bar/directory_a/new_file_in_directory': (u'obj', '0', '0'),
158 '/foo/bar/new_file': (u'obj', '0', '0'),
159 '/foo/bar/new_symlink': (u'obj', '0', '0')
160 }
161 RESULT_DICIONARY = TEST_PACKAGE_OLDCONTENTS.copy()
162 RESULT_DICIONARY.update(EXPECTED_NEW_ENTRIES)
163
164 mock_vartree.dbapi.writeContentsToContentsFile(mock_package,
Mike Frysingere65f3752014-12-08 00:46:39 -0500165 RESULT_DICIONARY)
Aviv Keshet940c17f2013-04-11 18:41:42 -0700166
Aviv Keshet940c17f2013-04-11 18:41:42 -0700167 change_report = autotest_quickmerge.ItemizeChangesFromRsyncOutput(
Mike Frysingere65f3752014-12-08 00:46:39 -0500168 RSYNC_TEST_OUTPUT, RSYNC_TEST_DESTINATION_PATH)
Aviv Keshet940c17f2013-04-11 18:41:42 -0700169 autotest_quickmerge.UpdatePackageContents(change_report, TEST_PACKAGE_CP,
Mike Frysingere65f3752014-12-08 00:46:39 -0500170 TEST_PORTAGE_ROOT)
Aviv Keshet940c17f2013-04-11 18:41:42 -0700171
Aviv Keshet940c17f2013-04-11 18:41:42 -0700172
Mike Frysingercc851fc2014-12-08 11:31:59 -0500173class PortageAPITest(cros_test_lib.TestCase):
Aviv Keshetb60fb3a2013-10-10 13:46:55 -0700174 """Ensures that required portage API exists."""
Mike Frysingere65f3752014-12-08 00:46:39 -0500175
Aviv Keshetb60fb3a2013-10-10 13:46:55 -0700176 def runTest(self):
177 try:
178 import portage
179 except ImportError:
180 self.skipTest('Portage not available in test environment. Re-run test '
181 'in chroot.')
182 try:
Mike Frysingere65f3752014-12-08 00:46:39 -0500183 # pylint: disable=no-member
Aviv Keshetb60fb3a2013-10-10 13:46:55 -0700184 f = portage.vardbapi.writeContentsToContentsFile
185 except AttributeError:
186 self.fail('Required writeContentsToContentsFile function does '
187 'not exist.')
Aviv Keshet940c17f2013-04-11 18:41:42 -0700188
Mike Frysingerca28b0e2019-10-13 21:13:48 -0400189 self.assertTrue(
190 callable(f),
191 msg='Required writeContentsToContentsFile is not a function.')