summaryrefslogtreecommitdiffstats
path: root/tests/test_git_superproject.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_git_superproject.py')
-rw-r--r--tests/test_git_superproject.py260
1 files changed, 227 insertions, 33 deletions
diff --git a/tests/test_git_superproject.py b/tests/test_git_superproject.py
index 9550949b..a24fc7f0 100644
--- a/tests/test_git_superproject.py
+++ b/tests/test_git_superproject.py
@@ -14,6 +14,7 @@
14 14
15"""Unittests for the git_superproject.py module.""" 15"""Unittests for the git_superproject.py module."""
16 16
17import json
17import os 18import os
18import platform 19import platform
19import tempfile 20import tempfile
@@ -21,13 +22,20 @@ import unittest
21from unittest import mock 22from unittest import mock
22 23
23import git_superproject 24import git_superproject
25import git_trace2_event_log
24import manifest_xml 26import manifest_xml
25import platform_utils 27import platform_utils
28from test_manifest_xml import sort_attributes
26 29
27 30
28class SuperprojectTestCase(unittest.TestCase): 31class SuperprojectTestCase(unittest.TestCase):
29 """TestCase for the Superproject module.""" 32 """TestCase for the Superproject module."""
30 33
34 PARENT_SID_KEY = 'GIT_TRACE2_PARENT_SID'
35 PARENT_SID_VALUE = 'parent_sid'
36 SELF_SID_REGEX = r'repo-\d+T\d+Z-.*'
37 FULL_SID_REGEX = r'^%s/%s' % (PARENT_SID_VALUE, SELF_SID_REGEX)
38
31 def setUp(self): 39 def setUp(self):
32 """Set up superproject every time.""" 40 """Set up superproject every time."""
33 self.tempdir = tempfile.mkdtemp(prefix='repo_tests') 41 self.tempdir = tempfile.mkdtemp(prefix='repo_tests')
@@ -37,6 +45,13 @@ class SuperprojectTestCase(unittest.TestCase):
37 os.mkdir(self.repodir) 45 os.mkdir(self.repodir)
38 self.platform = platform.system().lower() 46 self.platform = platform.system().lower()
39 47
48 # By default we initialize with the expected case where
49 # repo launches us (so GIT_TRACE2_PARENT_SID is set).
50 env = {
51 self.PARENT_SID_KEY: self.PARENT_SID_VALUE,
52 }
53 self.git_event_log = git_trace2_event_log.EventLog(env=env)
54
40 # The manifest parsing really wants a git repo currently. 55 # The manifest parsing really wants a git repo currently.
41 gitdir = os.path.join(self.repodir, 'manifests.git') 56 gitdir = os.path.join(self.repodir, 'manifests.git')
42 os.mkdir(gitdir) 57 os.mkdir(gitdir)
@@ -53,7 +68,8 @@ class SuperprojectTestCase(unittest.TestCase):
53 <project path="art" name="platform/art" groups="notdefault,platform-""" + self.platform + """ 68 <project path="art" name="platform/art" groups="notdefault,platform-""" + self.platform + """
54 " /></manifest> 69 " /></manifest>
55""") 70""")
56 self._superproject = git_superproject.Superproject(manifest, self.repodir) 71 self._superproject = git_superproject.Superproject(manifest, self.repodir,
72 self.git_event_log)
57 73
58 def tearDown(self): 74 def tearDown(self):
59 """Tear down superproject every time.""" 75 """Tear down superproject every time."""
@@ -65,14 +81,56 @@ class SuperprojectTestCase(unittest.TestCase):
65 fp.write(data) 81 fp.write(data)
66 return manifest_xml.XmlManifest(self.repodir, self.manifest_file) 82 return manifest_xml.XmlManifest(self.repodir, self.manifest_file)
67 83
84 def verifyCommonKeys(self, log_entry, expected_event_name, full_sid=True):
85 """Helper function to verify common event log keys."""
86 self.assertIn('event', log_entry)
87 self.assertIn('sid', log_entry)
88 self.assertIn('thread', log_entry)
89 self.assertIn('time', log_entry)
90
91 # Do basic data format validation.
92 self.assertEqual(expected_event_name, log_entry['event'])
93 if full_sid:
94 self.assertRegex(log_entry['sid'], self.FULL_SID_REGEX)
95 else:
96 self.assertRegex(log_entry['sid'], self.SELF_SID_REGEX)
97 self.assertRegex(log_entry['time'], r'^\d+-\d+-\d+T\d+:\d+:\d+\.\d+Z$')
98
99 def readLog(self, log_path):
100 """Helper function to read log data into a list."""
101 log_data = []
102 with open(log_path, mode='rb') as f:
103 for line in f:
104 log_data.append(json.loads(line))
105 return log_data
106
107 def verifyErrorEvent(self):
108 """Helper to verify that error event is written."""
109
110 with tempfile.TemporaryDirectory(prefix='event_log_tests') as tempdir:
111 log_path = self.git_event_log.Write(path=tempdir)
112 self.log_data = self.readLog(log_path)
113
114 self.assertEqual(len(self.log_data), 2)
115 error_event = self.log_data[1]
116 self.verifyCommonKeys(self.log_data[0], expected_event_name='version')
117 self.verifyCommonKeys(error_event, expected_event_name='error')
118 # Check for 'error' event specific fields.
119 self.assertIn('msg', error_event)
120 self.assertIn('fmt', error_event)
121
68 def test_superproject_get_superproject_no_superproject(self): 122 def test_superproject_get_superproject_no_superproject(self):
69 """Test with no url.""" 123 """Test with no url."""
70 manifest = self.getXmlManifest(""" 124 manifest = self.getXmlManifest("""
71<manifest> 125<manifest>
72</manifest> 126</manifest>
73""") 127""")
74 superproject = git_superproject.Superproject(manifest, self.repodir) 128 superproject = git_superproject.Superproject(manifest, self.repodir, self.git_event_log)
75 self.assertFalse(superproject.Sync()) 129 # Test that exit condition is false when there is no superproject tag.
130 sync_result = superproject.Sync()
131 self.assertFalse(sync_result.success)
132 self.assertFalse(sync_result.fatal)
133 self.verifyErrorEvent()
76 134
77 def test_superproject_get_superproject_invalid_url(self): 135 def test_superproject_get_superproject_invalid_url(self):
78 """Test with an invalid url.""" 136 """Test with an invalid url."""
@@ -83,8 +141,10 @@ class SuperprojectTestCase(unittest.TestCase):
83 <superproject name="superproject"/> 141 <superproject name="superproject"/>
84</manifest> 142</manifest>
85""") 143""")
86 superproject = git_superproject.Superproject(manifest, self.repodir) 144 superproject = git_superproject.Superproject(manifest, self.repodir, self.git_event_log)
87 self.assertFalse(superproject.Sync()) 145 sync_result = superproject.Sync()
146 self.assertFalse(sync_result.success)
147 self.assertTrue(sync_result.fatal)
88 148
89 def test_superproject_get_superproject_invalid_branch(self): 149 def test_superproject_get_superproject_invalid_branch(self):
90 """Test with an invalid branch.""" 150 """Test with an invalid branch."""
@@ -95,21 +155,28 @@ class SuperprojectTestCase(unittest.TestCase):
95 <superproject name="superproject"/> 155 <superproject name="superproject"/>
96</manifest> 156</manifest>
97""") 157""")
98 superproject = git_superproject.Superproject(manifest, self.repodir) 158 self._superproject = git_superproject.Superproject(manifest, self.repodir,
99 with mock.patch.object(self._superproject, '_GetBranch', return_value='junk'): 159 self.git_event_log)
100 self.assertFalse(superproject.Sync()) 160 with mock.patch.object(self._superproject, '_branch', 'junk'):
161 sync_result = self._superproject.Sync()
162 self.assertFalse(sync_result.success)
163 self.assertTrue(sync_result.fatal)
101 164
102 def test_superproject_get_superproject_mock_init(self): 165 def test_superproject_get_superproject_mock_init(self):
103 """Test with _Init failing.""" 166 """Test with _Init failing."""
104 with mock.patch.object(self._superproject, '_Init', return_value=False): 167 with mock.patch.object(self._superproject, '_Init', return_value=False):
105 self.assertFalse(self._superproject.Sync()) 168 sync_result = self._superproject.Sync()
169 self.assertFalse(sync_result.success)
170 self.assertTrue(sync_result.fatal)
106 171
107 def test_superproject_get_superproject_mock_fetch(self): 172 def test_superproject_get_superproject_mock_fetch(self):
108 """Test with _Fetch failing.""" 173 """Test with _Fetch failing."""
109 with mock.patch.object(self._superproject, '_Init', return_value=True): 174 with mock.patch.object(self._superproject, '_Init', return_value=True):
110 os.mkdir(self._superproject._superproject_path) 175 os.mkdir(self._superproject._superproject_path)
111 with mock.patch.object(self._superproject, '_Fetch', return_value=False): 176 with mock.patch.object(self._superproject, '_Fetch', return_value=False):
112 self.assertFalse(self._superproject.Sync()) 177 sync_result = self._superproject.Sync()
178 self.assertFalse(sync_result.success)
179 self.assertTrue(sync_result.fatal)
113 180
114 def test_superproject_get_all_project_commit_ids_mock_ls_tree(self): 181 def test_superproject_get_all_project_commit_ids_mock_ls_tree(self):
115 """Test with LsTree being a mock.""" 182 """Test with LsTree being a mock."""
@@ -121,12 +188,13 @@ class SuperprojectTestCase(unittest.TestCase):
121 with mock.patch.object(self._superproject, '_Init', return_value=True): 188 with mock.patch.object(self._superproject, '_Init', return_value=True):
122 with mock.patch.object(self._superproject, '_Fetch', return_value=True): 189 with mock.patch.object(self._superproject, '_Fetch', return_value=True):
123 with mock.patch.object(self._superproject, '_LsTree', return_value=data): 190 with mock.patch.object(self._superproject, '_LsTree', return_value=data):
124 commit_ids = self._superproject._GetAllProjectsCommitIds() 191 commit_ids_result = self._superproject._GetAllProjectsCommitIds()
125 self.assertEqual(commit_ids, { 192 self.assertEqual(commit_ids_result.commit_ids, {
126 'art': '2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea', 193 'art': '2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea',
127 'bootable/recovery': 'e9d25da64d8d365dbba7c8ee00fe8c4473fe9a06', 194 'bootable/recovery': 'e9d25da64d8d365dbba7c8ee00fe8c4473fe9a06',
128 'build/bazel': 'ade9b7a0d874e25fff4bf2552488825c6f111928' 195 'build/bazel': 'ade9b7a0d874e25fff4bf2552488825c6f111928'
129 }) 196 })
197 self.assertFalse(commit_ids_result.fatal)
130 198
131 def test_superproject_write_manifest_file(self): 199 def test_superproject_write_manifest_file(self):
132 """Test with writing manifest to a file after setting revisionId.""" 200 """Test with writing manifest to a file after setting revisionId."""
@@ -135,18 +203,18 @@ class SuperprojectTestCase(unittest.TestCase):
135 project.SetRevisionId('ABCDEF') 203 project.SetRevisionId('ABCDEF')
136 # Create temporary directory so that it can write the file. 204 # Create temporary directory so that it can write the file.
137 os.mkdir(self._superproject._superproject_path) 205 os.mkdir(self._superproject._superproject_path)
138 manifest_path = self._superproject._WriteManfiestFile() 206 manifest_path = self._superproject._WriteManifestFile()
139 self.assertIsNotNone(manifest_path) 207 self.assertIsNotNone(manifest_path)
140 with open(manifest_path, 'r') as fp: 208 with open(manifest_path, 'r') as fp:
141 manifest_xml = fp.read() 209 manifest_xml_data = fp.read()
142 self.assertEqual( 210 self.assertEqual(
143 manifest_xml, 211 sort_attributes(manifest_xml_data),
144 '<?xml version="1.0" ?><manifest>' + 212 '<?xml version="1.0" ?><manifest>'
145 '<remote name="default-remote" fetch="http://localhost"/>' + 213 '<remote fetch="http://localhost" name="default-remote"/>'
146 '<default remote="default-remote" revision="refs/heads/main"/>' + 214 '<default remote="default-remote" revision="refs/heads/main"/>'
147 '<project name="platform/art" path="art" revision="ABCDEF" ' + 215 '<project groups="notdefault,platform-' + self.platform + '" '
148 'groups="notdefault,platform-' + self.platform + '"/>' + 216 'name="platform/art" path="art" revision="ABCDEF" upstream="refs/heads/main"/>'
149 '<superproject name="superproject"/>' + 217 '<superproject name="superproject"/>'
150 '</manifest>') 218 '</manifest>')
151 219
152 def test_superproject_update_project_revision_id(self): 220 def test_superproject_update_project_revision_id(self):
@@ -162,19 +230,145 @@ class SuperprojectTestCase(unittest.TestCase):
162 return_value=data): 230 return_value=data):
163 # Create temporary directory so that it can write the file. 231 # Create temporary directory so that it can write the file.
164 os.mkdir(self._superproject._superproject_path) 232 os.mkdir(self._superproject._superproject_path)
165 manifest_path = self._superproject.UpdateProjectsRevisionId(projects) 233 update_result = self._superproject.UpdateProjectsRevisionId(projects)
166 self.assertIsNotNone(manifest_path) 234 self.assertIsNotNone(update_result.manifest_path)
167 with open(manifest_path, 'r') as fp: 235 self.assertFalse(update_result.fatal)
168 manifest_xml = fp.read() 236 with open(update_result.manifest_path, 'r') as fp:
237 manifest_xml_data = fp.read()
238 self.assertEqual(
239 sort_attributes(manifest_xml_data),
240 '<?xml version="1.0" ?><manifest>'
241 '<remote fetch="http://localhost" name="default-remote"/>'
242 '<default remote="default-remote" revision="refs/heads/main"/>'
243 '<project groups="notdefault,platform-' + self.platform + '" '
244 'name="platform/art" path="art" '
245 'revision="2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea" upstream="refs/heads/main"/>'
246 '<superproject name="superproject"/>'
247 '</manifest>')
248
249 def test_superproject_update_project_revision_id_no_superproject_tag(self):
250 """Test update of commit ids of a manifest without superproject tag."""
251 manifest = self.getXmlManifest("""
252<manifest>
253 <remote name="default-remote" fetch="http://localhost" />
254 <default remote="default-remote" revision="refs/heads/main" />
255 <project name="test-name"/>
256</manifest>
257""")
258 self.maxDiff = None
259 self._superproject = git_superproject.Superproject(manifest, self.repodir,
260 self.git_event_log)
261 self.assertEqual(len(self._superproject._manifest.projects), 1)
262 projects = self._superproject._manifest.projects
263 project = projects[0]
264 project.SetRevisionId('ABCDEF')
265 update_result = self._superproject.UpdateProjectsRevisionId(projects)
266 self.assertIsNone(update_result.manifest_path)
267 self.assertFalse(update_result.fatal)
268 self.verifyErrorEvent()
269 self.assertEqual(
270 sort_attributes(manifest.ToXml().toxml()),
271 '<?xml version="1.0" ?><manifest>'
272 '<remote fetch="http://localhost" name="default-remote"/>'
273 '<default remote="default-remote" revision="refs/heads/main"/>'
274 '<project name="test-name" revision="ABCDEF" upstream="refs/heads/main"/>'
275 '</manifest>')
276
277 def test_superproject_update_project_revision_id_from_local_manifest_group(self):
278 """Test update of commit ids of a manifest that have local manifest no superproject group."""
279 local_group = manifest_xml.LOCAL_MANIFEST_GROUP_PREFIX + ':local'
280 manifest = self.getXmlManifest("""
281<manifest>
282 <remote name="default-remote" fetch="http://localhost" />
283 <remote name="goog" fetch="http://localhost2" />
284 <default remote="default-remote" revision="refs/heads/main" />
285 <superproject name="superproject"/>
286 <project path="vendor/x" name="platform/vendor/x" remote="goog"
287 groups=\"""" + local_group + """
288 " revision="master-with-vendor" clone-depth="1" />
289 <project path="art" name="platform/art" groups="notdefault,platform-""" + self.platform + """
290 " /></manifest>
291""")
292 self.maxDiff = None
293 self._superproject = git_superproject.Superproject(manifest, self.repodir,
294 self.git_event_log)
295 self.assertEqual(len(self._superproject._manifest.projects), 2)
296 projects = self._superproject._manifest.projects
297 data = ('160000 commit 2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea\tart\x00')
298 with mock.patch.object(self._superproject, '_Init', return_value=True):
299 with mock.patch.object(self._superproject, '_Fetch', return_value=True):
300 with mock.patch.object(self._superproject,
301 '_LsTree',
302 return_value=data):
303 # Create temporary directory so that it can write the file.
304 os.mkdir(self._superproject._superproject_path)
305 update_result = self._superproject.UpdateProjectsRevisionId(projects)
306 self.assertIsNotNone(update_result.manifest_path)
307 self.assertFalse(update_result.fatal)
308 with open(update_result.manifest_path, 'r') as fp:
309 manifest_xml_data = fp.read()
310 # Verify platform/vendor/x's project revision hasn't changed.
311 self.assertEqual(
312 sort_attributes(manifest_xml_data),
313 '<?xml version="1.0" ?><manifest>'
314 '<remote fetch="http://localhost" name="default-remote"/>'
315 '<remote fetch="http://localhost2" name="goog"/>'
316 '<default remote="default-remote" revision="refs/heads/main"/>'
317 '<project groups="notdefault,platform-' + self.platform + '" '
318 'name="platform/art" path="art" '
319 'revision="2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea" upstream="refs/heads/main"/>'
320 '<project clone-depth="1" groups="' + local_group + '" '
321 'name="platform/vendor/x" path="vendor/x" remote="goog" '
322 'revision="master-with-vendor"/>'
323 '<superproject name="superproject"/>'
324 '</manifest>')
325
326 def test_superproject_update_project_revision_id_with_pinned_manifest(self):
327 """Test update of commit ids of a pinned manifest."""
328 manifest = self.getXmlManifest("""
329<manifest>
330 <remote name="default-remote" fetch="http://localhost" />
331 <default remote="default-remote" revision="refs/heads/main" />
332 <superproject name="superproject"/>
333 <project path="vendor/x" name="platform/vendor/x" revision="" />
334 <project path="vendor/y" name="platform/vendor/y"
335 revision="52d3c9f7c107839ece2319d077de0cd922aa9d8f" />
336 <project path="art" name="platform/art" groups="notdefault,platform-""" + self.platform + """
337 " /></manifest>
338""")
339 self.maxDiff = None
340 self._superproject = git_superproject.Superproject(manifest, self.repodir,
341 self.git_event_log)
342 self.assertEqual(len(self._superproject._manifest.projects), 3)
343 projects = self._superproject._manifest.projects
344 data = ('160000 commit 2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea\tart\x00'
345 '160000 commit e9d25da64d8d365dbba7c8ee00fe8c4473fe9a06\tvendor/x\x00')
346 with mock.patch.object(self._superproject, '_Init', return_value=True):
347 with mock.patch.object(self._superproject, '_Fetch', return_value=True):
348 with mock.patch.object(self._superproject,
349 '_LsTree',
350 return_value=data):
351 # Create temporary directory so that it can write the file.
352 os.mkdir(self._superproject._superproject_path)
353 update_result = self._superproject.UpdateProjectsRevisionId(projects)
354 self.assertIsNotNone(update_result.manifest_path)
355 self.assertFalse(update_result.fatal)
356 with open(update_result.manifest_path, 'r') as fp:
357 manifest_xml_data = fp.read()
358 # Verify platform/vendor/x's project revision hasn't changed.
169 self.assertEqual( 359 self.assertEqual(
170 manifest_xml, 360 sort_attributes(manifest_xml_data),
171 '<?xml version="1.0" ?><manifest>' + 361 '<?xml version="1.0" ?><manifest>'
172 '<remote name="default-remote" fetch="http://localhost"/>' + 362 '<remote fetch="http://localhost" name="default-remote"/>'
173 '<default remote="default-remote" revision="refs/heads/main"/>' + 363 '<default remote="default-remote" revision="refs/heads/main"/>'
174 '<project name="platform/art" path="art" ' + 364 '<project groups="notdefault,platform-' + self.platform + '" '
175 'revision="2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea" ' + 365 'name="platform/art" path="art" '
176 'groups="notdefault,platform-' + self.platform + '"/>' + 366 'revision="2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea" upstream="refs/heads/main"/>'
177 '<superproject name="superproject"/>' + 367 '<project name="platform/vendor/x" path="vendor/x" '
368 'revision="e9d25da64d8d365dbba7c8ee00fe8c4473fe9a06" upstream="refs/heads/main"/>'
369 '<project name="platform/vendor/y" path="vendor/y" '
370 'revision="52d3c9f7c107839ece2319d077de0cd922aa9d8f"/>'
371 '<superproject name="superproject"/>'
178 '</manifest>') 372 '</manifest>')
179 373
180 374