blob: 5487a891f9ab0390d8310e2dee3a0c17c29d61bd [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
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
Aviv Keshet940c17f2013-04-11 18:41:42 -070053RSYNC_TEST_DESTINATION_PATH = '/foo/bar/'
54
55TEST_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/'
60TEST_PACKAGE_OLDCONTENTS = {
Mike Frysingere65f3752014-12-08 00:46:39 -050061 u'/by/the/prickling/of/my/thumbs': (u'obj', '1234', '4321'),
62 u'/something/wicked/this/way/comes': (u'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):
Don Garrett25f309a2014-03-19 14:02:12 -070067 """Test autotest_quickmerge.ItemizeChangesFromRsyncOutput."""
Aviv Keshet787ffcd2013-04-08 15:14:56 -070068
69 def testItemizeChangesFromRsyncOutput(self):
70 """Test that rsync output parser returns correct FileMutations."""
Aviv Keshet787ffcd2013-04-08 15:14:56 -070071 expected_new = set(
72 [('>f+++++++++', '/foo/bar/new_file'),
73 ('>f+++++++++', '/foo/bar/directory_a/new_file_in_directory'),
74 ('cL+++++++++', '/foo/bar/new_symlink')])
75
76 expected_mod = set(
77 [('>f..t......', '/foo/bar/touched file with spaces'),
78 ('>f..t......', '/foo/bar/touched_file'),
79 ('>f.st......', '/foo/bar/modified_contents_file'),
80 ('.f...p.....', '/foo/bar/modified_permissions_file'),
81 ('.f....o....', '/foo/bar/modified_owner_file'),
82 ('>f..t......', '/foo/bar/directory_a/touched_file_in_directory')])
83
84 expected_dir = set([('cd+++++++++', '/foo/bar/new_empty_directory/')])
85
86 report = autotest_quickmerge.ItemizeChangesFromRsyncOutput(
Aviv Keshet940c17f2013-04-11 18:41:42 -070087 RSYNC_TEST_OUTPUT, RSYNC_TEST_DESTINATION_PATH)
Aviv Keshet787ffcd2013-04-08 15:14:56 -070088
89 self.assertEqual(expected_new, set(report.new_files))
90 self.assertEqual(expected_mod, set(report.modified_files))
91 self.assertEqual(expected_dir, set(report.new_directories))
92
93
Mike Frysingercc851fc2014-12-08 11:31:59 -050094class PackageNameParsingTest(cros_test_lib.TestCase):
Don Garrett25f309a2014-03-19 14:02:12 -070095 """Test autotest_quickmerge.GetStalePackageNames."""
Aviv Keshet75d65962013-04-17 16:15:23 -070096
97 def testGetStalePackageNames(self):
98 autotest_sysroot = '/an/arbitrary/path/'
99 change_report = autotest_quickmerge.ItemizeChangesFromRsyncOutput(
100 RSYNC_TEST_OUTPUT_FOR_PACKAGE_UPDATE, autotest_sysroot)
101 package_matches = autotest_quickmerge.GetStalePackageNames(
102 change_report.modified_files + change_report.new_files,
103 autotest_sysroot)
104 expected_set = set(['factory_Leds', 'login_UserPolicyKeys',
105 'platform_Cryptohome', 'power_Thermal'])
106 self.assertEqual(set(package_matches), expected_set)
107
108
Benjamin Gordon121a2aa2018-05-04 16:24:45 -0600109class RsyncCommandTest(cros_test_lib.RunCommandTestCase):
Don Garrett25f309a2014-03-19 14:02:12 -0700110 """Test autotest_quickmerge.RsyncQuickmerge."""
Aviv Keshetb1238c32013-04-01 11:42:13 -0700111
112 def testRsyncQuickmergeCommand(self):
Mike Frysinger45602c72019-09-22 02:15:11 -0400113 """Test that RsyncQuickMerge makes correct call to sudo_run"""
Aviv Keshetb1238c32013-04-01 11:42:13 -0700114 include_file_name = 'an_include_file_name'
115 source_path = 'a_source_path'
116 sysroot_path = 'a_sysroot_path'
117
118 expected_command = ['rsync', '-a', '-n', '-u', '-i',
119 '--exclude=**.pyc', '--exclude=**.pyo',
Aviv Keshet787ffcd2013-04-08 15:14:56 -0700120 '--exclude=** -> *',
Aviv Keshetb1238c32013-04-01 11:42:13 -0700121 '--include-from=%s' % include_file_name,
122 '--exclude=*',
123 source_path,
124 sysroot_path]
125
126 autotest_quickmerge.RsyncQuickmerge(source_path, sysroot_path,
127 include_file_name,
128 pretend=True,
Aviv Keshet60968ec2013-04-11 18:44:14 -0700129 overwrite=False)
Aviv Keshetb1238c32013-04-01 11:42:13 -0700130
131 self.assertCommandContains(expected_command)
132
133
Mike Frysingerc9785342014-12-08 00:47:08 -0500134class PortageManipulationsTest(cros_test_lib.MockTestCase):
Don Garrett25f309a2014-03-19 14:02:12 -0700135 """Test usage of autotest_quickmerge.portage."""
136
Aviv Keshet940c17f2013-04-11 18:41:42 -0700137 def testUpdatePackageContents(self):
138 """Test that UpdatePackageContents makes the correct calls to portage."""
Mike Frysingerc9785342014-12-08 00:47:08 -0500139 autotest_quickmerge.portage = mock.MagicMock()
Aviv Keshet940c17f2013-04-11 18:41:42 -0700140 portage = autotest_quickmerge.portage
141
142 portage.root = TEST_PORTAGE_ROOT
143
Mike Frysingerc9785342014-12-08 00:47:08 -0500144 mock_vartree = mock.MagicMock()
Aviv Keshet940c17f2013-04-11 18:41:42 -0700145 mock_vartree.settings = {'an arbitrary' : 'dictionary'}
146 mock_tree = {TEST_PORTAGE_ROOT : {'vartree' : mock_vartree}}
Mike Frysingerc9785342014-12-08 00:47:08 -0500147 portage.create_trees.return_value = mock_tree
Aviv Keshet940c17f2013-04-11 18:41:42 -0700148
Mike Frysingerc9785342014-12-08 00:47:08 -0500149 mock_vartree.dbapi = mock.MagicMock()
150 mock_vartree.dbapi.cp_list.return_value = [TEST_PACKAGE_CPV]
Aviv Keshet940c17f2013-04-11 18:41:42 -0700151
Mike Frysingerc9785342014-12-08 00:47:08 -0500152 mock_package = mock.MagicMock()
153 portage.dblink.return_value = mock_package # pylint: disable=no-member
154 mock_package.getcontents.return_value = TEST_PACKAGE_OLDCONTENTS
Aviv Keshet940c17f2013-04-11 18:41:42 -0700155
156 EXPECTED_NEW_ENTRIES = {
157 '/foo/bar/new_empty_directory': (u'dir',),
158 '/foo/bar/directory_a/new_file_in_directory': (u'obj', '0', '0'),
159 '/foo/bar/new_file': (u'obj', '0', '0'),
160 '/foo/bar/new_symlink': (u'obj', '0', '0')
161 }
162 RESULT_DICIONARY = TEST_PACKAGE_OLDCONTENTS.copy()
163 RESULT_DICIONARY.update(EXPECTED_NEW_ENTRIES)
164
165 mock_vartree.dbapi.writeContentsToContentsFile(mock_package,
Mike Frysingere65f3752014-12-08 00:46:39 -0500166 RESULT_DICIONARY)
Aviv Keshet940c17f2013-04-11 18:41:42 -0700167
Aviv Keshet940c17f2013-04-11 18:41:42 -0700168 change_report = autotest_quickmerge.ItemizeChangesFromRsyncOutput(
Mike Frysingere65f3752014-12-08 00:46:39 -0500169 RSYNC_TEST_OUTPUT, RSYNC_TEST_DESTINATION_PATH)
Aviv Keshet940c17f2013-04-11 18:41:42 -0700170 autotest_quickmerge.UpdatePackageContents(change_report, TEST_PACKAGE_CP,
Mike Frysingere65f3752014-12-08 00:46:39 -0500171 TEST_PORTAGE_ROOT)
Aviv Keshet940c17f2013-04-11 18:41:42 -0700172
Aviv Keshet940c17f2013-04-11 18:41:42 -0700173
Mike Frysingercc851fc2014-12-08 11:31:59 -0500174class PortageAPITest(cros_test_lib.TestCase):
Aviv Keshetb60fb3a2013-10-10 13:46:55 -0700175 """Ensures that required portage API exists."""
Mike Frysingere65f3752014-12-08 00:46:39 -0500176
Aviv Keshetb60fb3a2013-10-10 13:46:55 -0700177 def runTest(self):
178 try:
179 import portage
180 except ImportError:
181 self.skipTest('Portage not available in test environment. Re-run test '
182 'in chroot.')
183 try:
Mike Frysingere65f3752014-12-08 00:46:39 -0500184 # pylint: disable=no-member
Aviv Keshetb60fb3a2013-10-10 13:46:55 -0700185 f = portage.vardbapi.writeContentsToContentsFile
186 except AttributeError:
187 self.fail('Required writeContentsToContentsFile function does '
188 'not exist.')
Aviv Keshet940c17f2013-04-11 18:41:42 -0700189
Mike Frysingerca28b0e2019-10-13 21:13:48 -0400190 self.assertTrue(
191 callable(f),
192 msg='Required writeContentsToContentsFile is not a function.')