2 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Unittests for GerritHelper."""
12 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(
13 os.path.abspath(__file__)))))
15 from chromite.cbuildbot import constants
16 from chromite.lib import cros_build_lib
17 from chromite.lib import cros_test_lib
18 from chromite.lib import gerrit
19 from chromite.lib import gob_util
24 # pylint: disable=W0212,R0904
25 class GerritHelperTest(cros_test_lib.GerritTestCase):
26 """Unittests for GerritHelper."""
28 def _GetHelper(self, remote=constants.EXTERNAL_REMOTE):
29 return gerrit.GetGerritHelper(remote)
31 def createPatch(self, clone_path, project, amend=False):
32 """Create a patch in the given git checkout and upload it to gerrit.
35 clone_path: The directory on disk of the git clone.
36 project: The associated project.
37 amend: Whether to amend an existing patch. If set, we will amend the
38 HEAD commit in the checkout and upload that patch.
43 (revision, changeid) = self.createCommit(clone_path, amend=amend)
44 self.uploadChange(clone_path)
45 gpatch = self._GetHelper().QuerySingleRecord(
46 change=changeid, project=project, branch='master')
47 self.assertEqual(gpatch.change_id, changeid)
48 self.assertEqual(gpatch.revision, revision)
51 @cros_test_lib.NetworkTest()
52 def test001SimpleQuery(self):
53 """Create one independent and three dependent changes, then query them."""
54 project = self.createProject('test001')
55 clone_path = self.cloneProject(project)
56 (head_sha1, head_changeid) = self.createCommit(clone_path)
58 cros_build_lib.RunCommand(
59 ['git', 'checkout', head_sha1], cwd=clone_path, quiet=True)
60 self.createCommit(clone_path, fn='test-file-%d.txt' % idx)
61 self.uploadChange(clone_path)
62 helper = self._GetHelper()
63 changes = helper.Query(owner='self', project=project)
64 self.assertEqual(len(changes), 4)
65 changes = helper.Query(head_changeid, project=project, branch='master')
66 self.assertEqual(len(changes), 1)
67 self.assertEqual(changes[0].change_id, head_changeid)
68 self.assertEqual(changes[0].sha1, head_sha1)
69 change = helper.QuerySingleRecord(
70 head_changeid, project=project, branch='master')
71 self.assertTrue(change)
72 self.assertEqual(change.change_id, head_changeid)
73 self.assertEqual(change.sha1, head_sha1)
74 change = helper.GrabPatchFromGerrit(project, head_changeid, head_sha1)
75 self.assertTrue(change)
76 self.assertEqual(change.change_id, head_changeid)
77 self.assertEqual(change.sha1, head_sha1)
79 @cros_test_lib.NetworkTest()
80 @mock.patch.object(gerrit.GerritHelper, '_GERRIT_MAX_QUERY_RETURN', 2)
81 def test002GerritQueryTruncation(self):
82 """Verify that we detect gerrit truncating our query, and handle it."""
83 project = self.createProject('test002')
84 clone_path = self.cloneProject(project)
85 # Using a shell loop is markedly faster than running a python loop.
87 cmd = ('for ((i=0; i<%i; i=i+1)); do '
88 'echo "Another day, another dollar." > test-file-$i.txt; '
89 'git add test-file-$i.txt; '
90 'git commit -m "Test commit $i."; '
92 cros_build_lib.RunCommand(cmd, shell=True, cwd=clone_path, quiet=True)
93 self.uploadChange(clone_path)
94 helper = self._GetHelper()
95 changes = helper.Query(project=project)
96 self.assertEqual(len(changes), num_changes)
98 @cros_test_lib.NetworkTest()
99 def test003IsChangeCommitted(self):
100 """Tests that we can parse a json to check if a change is committed."""
101 project = self.createProject('test003')
102 clone_path = self.cloneProject(project)
103 gpatch = self.createPatch(clone_path, project)
104 helper = self._GetHelper()
105 helper.SetReview(gpatch.gerrit_number, labels={'Code-Review':'+2'})
106 helper.SubmitChange(gpatch)
107 self.assertTrue(helper.IsChangeCommitted(gpatch.gerrit_number))
109 gpatch = self.createPatch(clone_path, project)
110 self.assertFalse(helper.IsChangeCommitted(gpatch.gerrit_number))
112 @cros_test_lib.NetworkTest()
113 def test004GetLatestSHA1ForBranch(self):
114 """Verifies that we can query the tip-of-tree commit in a git repository."""
115 project = self.createProject('test004')
116 clone_path = self.cloneProject(project)
118 (master_sha1, _) = self.createCommit(clone_path)
119 self.pushBranch(clone_path, 'master')
121 (testbranch_sha1, _) = self.createCommit(clone_path)
122 self.pushBranch(clone_path, 'testbranch')
123 helper = self._GetHelper()
125 helper.GetLatestSHA1ForBranch(project, 'master'),
128 helper.GetLatestSHA1ForBranch(project, 'testbranch'),
131 def _ChooseReviewers(self):
132 all_reviewers = set(['dborowitz@google.com', 'sop@google.com',
134 ret = list(all_reviewers.difference(['%s@google.com' % getpass.getuser()]))
135 self.assertGreaterEqual(len(ret), 2)
138 @cros_test_lib.NetworkTest()
139 def test005SetReviewers(self):
140 """Verify that we can set reviewers on a CL."""
141 project = self.createProject('test005')
142 clone_path = self.cloneProject(project)
143 gpatch = self.createPatch(clone_path, project)
144 emails = self._ChooseReviewers()
145 helper = self._GetHelper()
146 helper.SetReviewers(gpatch.gerrit_number, add=(
147 emails[0], emails[1]))
148 reviewers = gob_util.GetReviewers(helper.host, gpatch.gerrit_number)
149 self.assertEqual(len(reviewers), 2)
150 self.assertItemsEqual(
151 [r['email'] for r in reviewers],
152 [emails[0], emails[1]])
153 helper.SetReviewers(gpatch.gerrit_number,
155 reviewers = gob_util.GetReviewers(helper.host, gpatch.gerrit_number)
156 self.assertEqual(len(reviewers), 1)
157 self.assertEqual(reviewers[0]['email'], emails[1])
159 @cros_test_lib.NetworkTest()
160 def test006PatchNotFound(self):
161 """Test case where ChangeID isn't found on the server."""
162 changeids = ['I' + ('deadbeef' * 5), 'I' + ('beadface' * 5)]
163 self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
165 self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
166 ['*' + cid for cid in changeids])
167 # Change ID sequence starts at 1000.
168 gerrit_numbers = ['123', '543']
169 self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
171 self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
172 ['*' + num for num in gerrit_numbers])
174 @cros_test_lib.NetworkTest()
175 def test007VagueQuery(self):
176 """Verify GerritHelper complains if an ID matches multiple changes."""
177 project = self.createProject('test007')
178 clone_path = self.cloneProject(project)
179 (sha1, _) = self.createCommit(clone_path)
180 (_, changeid) = self.createCommit(clone_path)
181 self.uploadChange(clone_path, 'master')
182 cros_build_lib.RunCommand(
183 ['git', 'checkout', sha1], cwd=clone_path, quiet=True)
184 self.createCommit(clone_path)
185 self.pushBranch(clone_path, 'testbranch')
187 clone_path, msg='Test commit.\n\nChange-Id: %s' % changeid)
188 self.uploadChange(clone_path, 'testbranch')
189 self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
192 @cros_test_lib.NetworkTest()
193 def test008Queries(self):
194 """Verify assorted query operations."""
195 project = self.createProject('test008')
196 clone_path = self.cloneProject(project)
197 gpatch = self.createPatch(clone_path, project)
198 helper = self._GetHelper()
200 # Multi-queries with one valid and one invalid term should raise.
201 invalid_change_id = 'I1234567890123456789012345678901234567890'
202 self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
203 [invalid_change_id, gpatch.change_id])
204 self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
205 [gpatch.change_id, invalid_change_id])
206 self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
207 ['12345', gpatch.gerrit_number])
208 self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
209 [gpatch.gerrit_number, '12345'])
211 # Simple query by project/changeid/sha1.
212 patch_info = helper.GrabPatchFromGerrit(gpatch.project, gpatch.change_id,
214 self.assertEqual(patch_info.gerrit_number, gpatch.gerrit_number)
215 self.assertEqual(patch_info.remote, constants.EXTERNAL_REMOTE)
217 # Simple query by gerrit number to external remote.
218 patch_info = gerrit.GetGerritPatchInfo([gpatch.gerrit_number])
219 self.assertEqual(patch_info[0].gerrit_number, gpatch.gerrit_number)
220 self.assertEqual(patch_info[0].remote, constants.EXTERNAL_REMOTE)
222 # Simple query by gerrit number to internal remote.
223 patch_info = gerrit.GetGerritPatchInfo(['*' + gpatch.gerrit_number])
224 self.assertEqual(patch_info[0].gerrit_number, gpatch.gerrit_number)
225 self.assertEqual(patch_info[0].remote, constants.INTERNAL_REMOTE)
227 # Query to external server by gerrit number and change-id which refer to
228 # the same change should return one result.
229 fq_changeid = '~'.join((gpatch.project, 'master', gpatch.change_id))
230 patch_info = gerrit.GetGerritPatchInfo([gpatch.gerrit_number, fq_changeid])
231 self.assertEqual(len(patch_info), 1)
232 self.assertEqual(patch_info[0].gerrit_number, gpatch.gerrit_number)
233 self.assertEqual(patch_info[0].remote, constants.EXTERNAL_REMOTE)
235 # Query to internal server by gerrit number and change-id which refer to
236 # the same change should return one result.
237 patch_info = gerrit.GetGerritPatchInfo(
238 ['*' + gpatch.gerrit_number, '*' + fq_changeid])
239 self.assertEqual(len(patch_info), 1)
240 self.assertEqual(patch_info[0].gerrit_number, gpatch.gerrit_number)
241 self.assertEqual(patch_info[0].remote, constants.INTERNAL_REMOTE)
243 @cros_test_lib.NetworkTest()
244 def test009SubmitOutdatedCommit(self):
245 """Tests that we can parse a json to check if a change is committed."""
246 project = self.createProject('test009')
247 clone_path = self.cloneProject(project)
250 gpatch1 = self.createPatch(clone_path, project)
253 gpatch2 = self.createPatch(clone_path, project, amend=True)
255 # Make sure we're talking about the same change.
256 self.assertEqual(gpatch1.change_id, gpatch2.change_id)
258 # Try submitting the out-of-date change.
259 helper = self._GetHelper()
260 helper.SetReview(gpatch1.gerrit_number, labels={'Code-Review':'+2'})
261 with self.assertRaises(gob_util.GOBError) as ex:
262 helper.SubmitChange(gpatch1)
263 self.assertEqual(ex.exception.http_status, httplib.CONFLICT)
264 self.assertFalse(helper.IsChangeCommitted(gpatch1.gerrit_number))
266 # Try submitting the up-to-date change.
267 helper.SubmitChange(gpatch2)
268 self.assertTrue(helper.IsChangeCommitted(gpatch2.gerrit_number))
271 if __name__ == '__main__':