blob: 73447b47355f8df49226ac9e11bb40dec7ff8d43 [file] [log] [blame]
maruel@chromium.orgddd59412011-11-30 14:20:38 +00001#!/usr/bin/env python
maruel@chromium.orgeb5edbc2012-01-16 17:03:28 +00002# Copyright (c) 2012 The Chromium Authors. All rights reserved.
maruel@chromium.orgddd59412011-11-30 14:20:38 +00003# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Unit tests for git_cl.py."""
7
8import os
maruel@chromium.orga3353652011-11-30 14:26:57 +00009import StringIO
ukai@chromium.org78c4b982012-02-14 02:20:26 +000010import stat
maruel@chromium.orgddd59412011-11-30 14:20:38 +000011import sys
12import unittest
13
14sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
15
16from testing_support.auto_stub import TestCase
17
18import git_cl
19import subprocess2
20
21
maruel@chromium.org2e72bb12012-01-17 15:18:35 +000022class PresubmitMock(object):
23 def __init__(self, *args, **kwargs):
24 self.reviewers = []
25 @staticmethod
26 def should_continue():
27 return True
28
29
30class RietveldMock(object):
31 def __init__(self, *args, **kwargs):
32 pass
33 @staticmethod
34 def get_description(issue):
35 return 'Issue: %d' % issue
36
37
38class WatchlistsMock(object):
39 def __init__(self, _):
40 pass
41 @staticmethod
42 def GetWatchersForPaths(_):
43 return ['joe@example.com']
44
45
ukai@chromium.org78c4b982012-02-14 02:20:26 +000046class CodereviewSettingsFileMock(object):
47 def __init__(self):
48 pass
49 # pylint: disable=R0201
50 def read(self):
51 return ("CODE_REVIEW_SERVER: gerrit.chromium.org\n" +
52 "GERRIT_HOST: gerrit.chromium.org\n" +
53 "GERRIT_PORT: 29418\n")
54
55
maruel@chromium.orgddd59412011-11-30 14:20:38 +000056class TestGitCl(TestCase):
57 def setUp(self):
58 super(TestGitCl, self).setUp()
59 self.calls = []
60 self._calls_done = 0
maruel@chromium.org2e72bb12012-01-17 15:18:35 +000061 self.mock(subprocess2, 'call', self._mocked_call)
62 self.mock(subprocess2, 'check_call', self._mocked_call)
63 self.mock(subprocess2, 'check_output', self._mocked_call)
64 self.mock(subprocess2, 'communicate', self._mocked_call)
65 self.mock(subprocess2, 'Popen', self._mocked_call)
maruel@chromium.orgddd59412011-11-30 14:20:38 +000066 self.mock(git_cl, 'FindCodereviewSettingsFile', lambda: '')
maruel@chromium.org2e72bb12012-01-17 15:18:35 +000067 self.mock(git_cl, 'ask_for_data', self._mocked_call)
68 self.mock(git_cl.breakpad, 'post', self._mocked_call)
69 self.mock(git_cl.breakpad, 'SendStack', self._mocked_call)
maruel@chromium.orgddd59412011-11-30 14:20:38 +000070 self.mock(git_cl.presubmit_support, 'DoPresubmitChecks', PresubmitMock)
maruel@chromium.orgddd59412011-11-30 14:20:38 +000071 self.mock(git_cl.rietveld, 'Rietveld', RietveldMock)
maruel@chromium.orgddd59412011-11-30 14:20:38 +000072 self.mock(git_cl.upload, 'RealMain', self.fail)
maruel@chromium.orgddd59412011-11-30 14:20:38 +000073 self.mock(git_cl.watchlists, 'Watchlists', WatchlistsMock)
74 # It's important to reset settings to not have inter-tests interference.
75 git_cl.settings = None
76
77 def tearDown(self):
78 if not self.has_failed():
79 self.assertEquals([], self.calls)
80 super(TestGitCl, self).tearDown()
81
maruel@chromium.org2e72bb12012-01-17 15:18:35 +000082 def _mocked_call(self, *args, **kwargs):
83 self.assertTrue(
84 self.calls,
85 '@%d Expected: <Missing> Actual: %r' % (self._calls_done, args))
86 expected_args, result = self.calls.pop(0)
87 self.assertEquals(
88 expected_args,
89 args,
90 '@%d Expected: %r Actual: %r' % (
91 self._calls_done, expected_args, args))
92 self._calls_done += 1
93 return result
94
maruel@chromium.orga3353652011-11-30 14:26:57 +000095 @classmethod
iannucci@chromium.org79540052012-10-19 23:15:26 +000096 def _upload_calls(cls, similarity, find_copies):
97 return (cls._git_base_calls(similarity, find_copies) +
98 cls._git_upload_calls())
maruel@chromium.orga3353652011-11-30 14:26:57 +000099
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000100 @classmethod
101 def _git_base_calls(cls, similarity, find_copies):
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000102 if similarity is None:
103 similarity = '50'
104 similarity_call = ((['git', 'config', '--int', '--get',
105 'branch.master.git-cl-similarity'],), '')
106 else:
107 similarity_call = ((['git', 'config', '--int',
108 'branch.master.git-cl-similarity', similarity],), '')
iannucci@chromium.org79540052012-10-19 23:15:26 +0000109
110 if find_copies is None:
111 find_copies = True
112 find_copies_call = ((['git', 'config', '--int', '--get',
113 'branch.master.git-find-copies'],), '')
114 else:
115 val = str(int(find_copies))
116 find_copies_call = ((['git', 'config', '--int',
117 'branch.master.git-find-copies', val],), '')
118
119 if find_copies:
120 stat_call = ((['git', 'diff', '--no-ext-diff', '--stat',
121 '--find-copies-harder', '-l100000', '-C'+similarity,
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000122 'fake_ancestor_sha'],), '+dat')
iannucci@chromium.org79540052012-10-19 23:15:26 +0000123 else:
124 stat_call = ((['git', 'diff', '--no-ext-diff', '--stat',
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000125 '-M'+similarity, 'fake_ancestor_sha'],), '+dat')
iannucci@chromium.org79540052012-10-19 23:15:26 +0000126
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000127 return [
ukai@chromium.orge8077812012-02-03 03:41:46 +0000128 ((['git', 'config', 'gerrit.host'],), ''),
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000129 ((['git', 'config', 'rietveld.server'],), 'codereview.example.com'),
130 ((['git', 'symbolic-ref', 'HEAD'],), 'master'),
131 similarity_call,
iannucci@chromium.org79540052012-10-19 23:15:26 +0000132 ((['git', 'symbolic-ref', 'HEAD'],), 'master'),
133 find_copies_call,
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000134 ((['git', 'update-index', '--refresh', '-q'],), ''),
ukai@chromium.org259e4682012-10-25 07:36:33 +0000135 ((['git', 'diff-index', '--name-status', 'HEAD'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000136 ((['git', 'symbolic-ref', 'HEAD'],), 'master'),
137 ((['git', 'config', 'branch.master.merge'],), 'master'),
138 ((['git', 'config', 'branch.master.remote'],), 'origin'),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000139 ((['git', 'merge-base', 'master', 'HEAD'],), 'fake_ancestor_sha'),
140 ] + cls._git_sanity_checks('fake_ancestor_sha', 'master') + [
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000141 ((['git', 'rev-parse', '--show-cdup'],), ''),
142 ((['git', 'rev-parse', 'HEAD'],), '12345'),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000143 ((['git', 'diff', '--name-status', '-r', 'fake_ancestor_sha...', '.'],),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000144 'M\t.gitignore\n'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000145 ((['git', 'config', 'branch.master.rietveldissue'],), ''),
146 ((['git', 'config', 'branch.master.rietveldpatchset'],), ''),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000147 ((['git', 'log', '--pretty=format:%s%n%n%b', 'fake_ancestor_sha...'],),
148 'foo'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000149 ((['git', 'config', 'user.email'],), 'me@example.com'),
iannucci@chromium.org79540052012-10-19 23:15:26 +0000150 stat_call,
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000151 ((['git', 'log', '--pretty=format:%s\n\n%b', 'fake_ancestor_sha..'],),
152 'desc\n'),
maruel@chromium.orga3353652011-11-30 14:26:57 +0000153 ]
154
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000155 @classmethod
156 def _git_upload_calls(cls):
maruel@chromium.orga3353652011-11-30 14:26:57 +0000157 return [
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000158 ((['git', 'config', 'rietveld.cc'],), ''),
kalmard@homejinni.com6b0051e2012-04-03 15:45:08 +0000159 ((['git', 'config', 'branch.master.base-url'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000160 ((['git', 'config', '--get-regexp', '^svn-remote\\.'],),
161 (('', None), 0)),
162 ((['git', 'rev-parse', '--show-cdup'],), ''),
163 ((['git', 'svn', 'info'],), ''),
164 ((['git', 'config', 'branch.master.rietveldissue', '1'],), ''),
165 ((['git', 'config', 'branch.master.rietveldserver',
166 'https://codereview.example.com'],), ''),
167 ((['git', 'config', 'branch.master.rietveldpatchset', '2'],), ''),
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000168 ]
169
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000170 @staticmethod
171 def _git_sanity_checks(diff_base, working_branch):
172 fake_ancestor = 'fake_ancestor'
173 fake_cl = 'fake_cl_for_patch'
174 return [
175 # Calls to verify branch point is ancestor
176 ((['git', 'rev-parse', '--verify', diff_base],), fake_ancestor),
177 ((['git', 'merge-base', fake_ancestor, 'HEAD'],), fake_ancestor),
178 ((['git', 'rev-list', '^' + fake_ancestor, 'HEAD'],), fake_cl),
179 # Mock a config miss (error code 1)
180 ((['git', 'config', 'gitcl.remotebranch'],), (('', None), 1)),
181 # Call to GetRemoteBranch()
182 ((['git', 'config', 'branch.%s.merge' % working_branch],),
183 'refs/heads/master'),
184 ((['git', 'config', 'branch.%s.remote' % working_branch],), 'origin'),
185 ((['git', 'rev-list', '^' + fake_ancestor,
186 'refs/remotes/origin/master'],), ''),
187 ]
188
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000189 @classmethod
190 def _dcommit_calls_1(cls):
191 return [
192 ((['git', 'config', '--get-regexp', '^svn-remote\\.'],),
193 ((('svn-remote.svn.url svn://svn.chromium.org/chrome\n'
194 'svn-remote.svn.fetch trunk/src:refs/remotes/origin/master'),
195 None),
196 0)),
197 ((['git', 'config', 'rietveld.server'],), 'codereview.example.com'),
198 ((['git', 'symbolic-ref', 'HEAD'],), 'refs/heads/working'),
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000199 ((['git', 'config', '--int', '--get',
200 'branch.working.git-cl-similarity'],), ''),
201 ((['git', 'symbolic-ref', 'HEAD'],), 'refs/heads/working'),
iannucci@chromium.org79540052012-10-19 23:15:26 +0000202 ((['git', 'config', '--int', '--get',
203 'branch.working.git-find-copies'],), ''),
204 ((['git', 'symbolic-ref', 'HEAD'],), 'refs/heads/working'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000205 ((['git', 'config', 'branch.working.merge'],), 'refs/heads/master'),
206 ((['git', 'config', 'branch.working.remote'],), 'origin'),
szager@chromium.org9bb85e22012-06-13 20:28:23 +0000207 ((['git', 'rev-list', '--merges',
szager@chromium.orge84b7542012-06-15 21:26:58 +0000208 '--grep=^SVN changes up to revision [0-9]*$',
szager@chromium.org9bb85e22012-06-13 20:28:23 +0000209 'refs/remotes/origin/master^!'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000210 ((['git', 'update-index', '--refresh', '-q'],), ''),
ukai@chromium.org259e4682012-10-25 07:36:33 +0000211 ((['git', 'diff-index', '--name-status', 'HEAD'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000212 ((['git', 'rev-list', '^refs/heads/working',
213 'refs/remotes/origin/master'],),
214 ''),
215 ((['git', 'log', '--grep=^git-svn-id:', '-1', '--pretty=format:%H'],),
216 '3fc18b62c4966193eb435baabe2d18a3810ec82e'),
217 ((['git', 'rev-list', '^3fc18b62c4966193eb435baabe2d18a3810ec82e',
218 'refs/remotes/origin/master'],), ''),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000219 ((['git', 'merge-base', 'refs/remotes/origin/master', 'HEAD'],),
220 'fake_ancestor_sha'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000221 ]
222
223 @classmethod
224 def _dcommit_calls_normal(cls):
225 return [
226 ((['git', 'rev-parse', '--show-cdup'],), ''),
227 ((['git', 'rev-parse', 'HEAD'],),
228 '00ff397798ea57439712ed7e04ab96e13969ef40'),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000229 ((['git', 'diff', '--name-status', '-r', 'fake_ancestor_sha...',
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000230 '.'],),
231 'M\tPRESUBMIT.py'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000232 ((['git', 'config', 'branch.working.rietveldissue'],), '12345'),
evan@chromium.org0af9b702012-02-11 00:42:16 +0000233 ((['git', 'config', 'branch.working.rietveldpatchset'],), '31137'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000234 ((['git', 'config', 'branch.working.rietveldserver'],),
235 'codereview.example.com'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000236 ((['git', 'config', 'user.email'],), 'author@example.com'),
237 ((['git', 'config', 'rietveld.tree-status-url'],), ''),
238 ]
239
240 @classmethod
241 def _dcommit_calls_bypassed(cls):
242 return [
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000243 ((['git', 'config', 'branch.working.rietveldissue'],), '12345'),
244 ((['git', 'config', 'branch.working.rietveldserver'],),
245 'codereview.example.com'),
246 (('GitClHooksBypassedCommit',
247 'Issue https://codereview.example.com/12345 bypassed hook when '
248 'committing'), None),
249 ]
250
251 @classmethod
252 def _dcommit_calls_3(cls):
253 return [
maruel@chromium.org49e3d802012-07-18 23:54:45 +0000254 ((['git', 'diff', '--no-ext-diff', '--stat', '--find-copies-harder',
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000255 '-l100000', '-C50', 'fake_ancestor_sha',
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000256 'refs/heads/working'],),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000257 (' PRESUBMIT.py | 2 +-\n'
258 ' 1 files changed, 1 insertions(+), 1 deletions(-)\n')),
259 (('About to commit; enter to confirm.',), None),
260 ((['git', 'show-ref', '--quiet', '--verify',
261 'refs/heads/git-cl-commit'],),
262 (('', None), 0)),
263 ((['git', 'branch', '-D', 'git-cl-commit'],), ''),
szager@chromium.org9bb85e22012-06-13 20:28:23 +0000264 ((['git', 'show-ref', '--quiet', '--verify',
265 'refs/heads/git-cl-cherry-pick'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000266 ((['git', 'rev-parse', '--show-cdup'],), '\n'),
267 ((['git', 'checkout', '-q', '-b', 'git-cl-commit'],), ''),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000268 ((['git', 'reset', '--soft', 'fake_ancestor_sha'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000269 ((['git', 'commit', '-m',
270 'Issue: 12345\n\nReview URL: https://codereview.example.com/12345'],),
271 ''),
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000272 ((['git', 'svn', 'dcommit', '-C50', '--no-rebase', '--rmdir'],),
273 (('', None), 0)),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000274 ((['git', 'checkout', '-q', 'working'],), ''),
275 ((['git', 'branch', '-D', 'git-cl-commit'],), ''),
276 ]
277
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000278 @staticmethod
iannucci@chromium.org79540052012-10-19 23:15:26 +0000279 def _cmd_line(description, args, similarity, find_copies):
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000280 """Returns the upload command line passed to upload.RealMain()."""
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000281 return [
282 'upload', '--assume_yes', '--server',
maruel@chromium.orgeb5edbc2012-01-16 17:03:28 +0000283 'https://codereview.example.com',
maruel@chromium.org71e12a92012-02-14 02:34:15 +0000284 '--message', description
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000285 ] + args + [
286 '--cc', 'joe@example.com',
iannucci@chromium.org79540052012-10-19 23:15:26 +0000287 '--git_similarity', similarity or '50'
288 ] + (['--git_no_find_copies'] if find_copies == False else []) + [
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000289 'fake_ancestor_sha'
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000290 ]
291
292 def _run_reviewer_test(
293 self,
294 upload_args,
295 expected_description,
296 returned_description,
297 final_description,
298 reviewers):
299 """Generic reviewer test framework."""
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000300 try:
301 similarity = upload_args[upload_args.index('--similarity')+1]
302 except ValueError:
303 similarity = None
iannucci@chromium.org79540052012-10-19 23:15:26 +0000304
305 if '--find-copies' in upload_args:
306 find_copies = True
307 elif '--no-find-copies' in upload_args:
308 find_copies = False
309 else:
310 find_copies = None
311
312 self.calls = self._upload_calls(similarity, find_copies)
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000313 def RunEditor(desc, _):
314 self.assertEquals(
315 '# Enter a description of the change.\n'
316 '# This will displayed on the codereview site.\n'
317 '# The first line will also be used as the subject of the review.\n' +
318 expected_description,
319 desc)
320 return returned_description
321 self.mock(git_cl.gclient_utils, 'RunEditor', RunEditor)
322 def check_upload(args):
iannucci@chromium.org79540052012-10-19 23:15:26 +0000323 cmd_line = self._cmd_line(final_description, reviewers, similarity,
324 find_copies)
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000325 self.assertEquals(cmd_line, args)
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000326 return 1, 2
327 self.mock(git_cl.upload, 'RealMain', check_upload)
328 git_cl.main(['upload'] + upload_args)
329
330 def test_no_reviewer(self):
331 self._run_reviewer_test(
332 [],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000333 'desc\n\nBUG=\n',
334 '# Blah blah comment.\ndesc\n\nBUG=\n',
335 'desc\n\nBUG=\n',
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000336 [])
337
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000338 def test_keep_similarity(self):
339 self._run_reviewer_test(
340 ['--similarity', '70'],
341 'desc\n\nBUG=\n',
342 '# Blah blah comment.\ndesc\n\nBUG=\n',
343 'desc\n\nBUG=\n',
344 [])
345
iannucci@chromium.org79540052012-10-19 23:15:26 +0000346 def test_keep_find_copies(self):
347 self._run_reviewer_test(
348 ['--no-find-copies'],
349 'desc\n\nBUG=\n',
350 '# Blah blah comment.\ndesc\n\nBUG=\n',
351 'desc\n\nBUG=\n',
352 [])
353
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000354 def test_reviewers_cmd_line(self):
355 # Reviewer is passed as-is
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000356 description = 'desc\n\nR=foo@example.com\nBUG=\n'
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000357 self._run_reviewer_test(
358 ['-r' 'foo@example.com'],
359 description,
360 '\n%s\n' % description,
361 description,
362 ['--reviewers', 'foo@example.com'])
363
364 def test_reviewer_tbr_overriden(self):
365 # Reviewer is overriden with TBR
366 # Also verifies the regexp work without a trailing LF
367 description = 'Foo Bar\nTBR=reviewer@example.com\n'
368 self._run_reviewer_test(
369 ['-r' 'foo@example.com'],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000370 'desc\n\nR=foo@example.com\nBUG=\n',
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000371 description.strip('\n'),
372 description,
373 ['--reviewers', 'reviewer@example.com'])
374
375 def test_reviewer_multiple(self):
376 # Handles multiple R= or TBR= lines.
377 description = (
378 'Foo Bar\nTBR=reviewer@example.com\nBUG=\nR=another@example.com\n')
379 self._run_reviewer_test(
380 [],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000381 'desc\n\nBUG=\n',
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000382 description,
383 description,
384 ['--reviewers', 'reviewer@example.com,another@example.com'])
385
maruel@chromium.orga3353652011-11-30 14:26:57 +0000386 def test_reviewer_send_mail(self):
387 # --send-mail can be used without -r if R= is used
388 description = 'Foo Bar\nR=reviewer@example.com\n'
389 self._run_reviewer_test(
390 ['--send-mail'],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000391 'desc\n\nBUG=\n',
maruel@chromium.orga3353652011-11-30 14:26:57 +0000392 description.strip('\n'),
393 description,
394 ['--reviewers', 'reviewer@example.com', '--send_mail'])
395
396 def test_reviewer_send_mail_no_rev(self):
397 # Fails without a reviewer.
398 class FileMock(object):
399 buf = StringIO.StringIO()
400 def write(self, content):
401 self.buf.write(content)
402
403 mock = FileMock()
404 try:
iannucci@chromium.org79540052012-10-19 23:15:26 +0000405 self.calls = self._git_base_calls(None, None)
maruel@chromium.orga3353652011-11-30 14:26:57 +0000406 def RunEditor(desc, _):
407 return desc
408 self.mock(git_cl.gclient_utils, 'RunEditor', RunEditor)
409 self.mock(sys, 'stderr', mock)
410 git_cl.main(['upload', '--send-mail'])
411 self.fail()
412 except SystemExit:
413 self.assertEquals(
414 'Must specify reviewers to send email.\n', mock.buf.getvalue())
415
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000416 def test_dcommit(self):
417 self.calls = (
418 self._dcommit_calls_1() +
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000419 self._git_sanity_checks('fake_ancestor_sha', 'working') +
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000420 self._dcommit_calls_normal() +
421 self._dcommit_calls_3())
422 git_cl.main(['dcommit'])
423
424 def test_dcommit_bypass_hooks(self):
425 self.calls = (
426 self._dcommit_calls_1() +
427 self._dcommit_calls_bypassed() +
428 self._dcommit_calls_3())
429 git_cl.main(['dcommit', '--bypass-hooks'])
430
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000431
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000432 @classmethod
433 def _gerrit_base_calls(cls):
ukai@chromium.orge8077812012-02-03 03:41:46 +0000434 return [
435 ((['git', 'config', 'gerrit.host'],), 'gerrit.example.com'),
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000436 ((['git', 'config', 'rietveld.server'],), 'codereview.example.com'),
437 ((['git', 'symbolic-ref', 'HEAD'],), 'master'),
438 ((['git', 'config', '--int', '--get',
439 'branch.master.git-cl-similarity'],), ''),
iannucci@chromium.org79540052012-10-19 23:15:26 +0000440 ((['git', 'symbolic-ref', 'HEAD'],), 'master'),
441 ((['git', 'config', '--int', '--get',
442 'branch.master.git-find-copies'],), ''),
ukai@chromium.orge8077812012-02-03 03:41:46 +0000443 ((['git', 'update-index', '--refresh', '-q'],), ''),
ukai@chromium.org259e4682012-10-25 07:36:33 +0000444 ((['git', 'diff-index', '--name-status', 'HEAD'],), ''),
ukai@chromium.orge8077812012-02-03 03:41:46 +0000445 ((['git', 'symbolic-ref', 'HEAD'],), 'master'),
446 ((['git', 'config', 'branch.master.merge'],), 'master'),
447 ((['git', 'config', 'branch.master.remote'],), 'origin'),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000448 ((['git', 'merge-base', 'master', 'HEAD'],), 'fake_ancestor_sha'),
449 ] + cls._git_sanity_checks('fake_ancestor_sha', 'master') + [
ukai@chromium.orge8077812012-02-03 03:41:46 +0000450 ((['git', 'rev-parse', '--show-cdup'],), ''),
451 ((['git', 'rev-parse', 'HEAD'],), '12345'),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000452 ((['git', 'diff', '--name-status', '-r', 'fake_ancestor_sha...', '.'],),
ukai@chromium.orge8077812012-02-03 03:41:46 +0000453 'M\t.gitignore\n'),
ukai@chromium.orge8077812012-02-03 03:41:46 +0000454 ((['git', 'config', 'branch.master.rietveldissue'],), ''),
455 ((['git', 'config', 'branch.master.rietveldpatchset'],), ''),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000456 ((['git', 'log', '--pretty=format:%s%n%n%b', 'fake_ancestor_sha...'],),
457 'foo'),
ukai@chromium.orge8077812012-02-03 03:41:46 +0000458 ((['git', 'config', 'user.email'],), 'me@example.com'),
cmp@chromium.org5cf70222012-06-12 18:20:13 +0000459 ((['git', 'diff', '--no-ext-diff', '--stat', '--find-copies-harder',
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000460 '-l100000', '-C50', 'fake_ancestor_sha'],),
ukai@chromium.orge8077812012-02-03 03:41:46 +0000461 '+dat'),
462 ]
463
464 @staticmethod
465 def _gerrit_upload_calls(description, reviewers):
466 calls = [
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000467 ((['git', 'log', '--pretty=format:%s\n\n%b', 'fake_ancestor_sha..'],),
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000468 description)
469 ]
470 if git_cl.CHANGE_ID not in description:
471 calls += [
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000472 ((['git', 'log', '--pretty=format:%s\n\n%b', 'fake_ancestor_sha..'],),
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000473 description),
474 ((['git', 'commit', '--amend', '-m', description],),
475 ''),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000476 ((['git', 'log', '--pretty=format:%s\n\n%b', 'fake_ancestor_sha..'],),
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000477 description)
478 ]
479 calls += [
ukai@chromium.orge8077812012-02-03 03:41:46 +0000480 ((['git', 'config', 'rietveld.cc'],), '')
481 ]
ukai@chromium.org19bbfa22012-02-03 16:18:11 +0000482 receive_pack = '--receive-pack=git receive-pack '
ukai@chromium.orge8077812012-02-03 03:41:46 +0000483 receive_pack += '--cc=joe@example.com' # from watch list
484 if reviewers:
485 receive_pack += ' '
486 receive_pack += ' '.join(['--reviewer=' + email for email in reviewers])
ukai@chromium.org19bbfa22012-02-03 16:18:11 +0000487 receive_pack += ''
ukai@chromium.orge8077812012-02-03 03:41:46 +0000488 calls += [
489 ((['git', 'push', receive_pack, 'origin', 'HEAD:refs/for/master'],),
490 '')
491 ]
492 return calls
493
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000494 def _run_gerrit_upload_test(
ukai@chromium.orge8077812012-02-03 03:41:46 +0000495 self,
496 upload_args,
497 description,
498 reviewers):
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000499 """Generic gerrit upload test framework."""
ukai@chromium.orge8077812012-02-03 03:41:46 +0000500 self.calls = self._gerrit_base_calls()
501 self.calls += self._gerrit_upload_calls(description, reviewers)
502 git_cl.main(['upload'] + upload_args)
503
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000504 def test_gerrit_upload_without_change_id(self):
505 self._run_gerrit_upload_test(
ukai@chromium.orge8077812012-02-03 03:41:46 +0000506 [],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000507 'desc\n\nBUG=\n',
ukai@chromium.orge8077812012-02-03 03:41:46 +0000508 [])
509
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000510 def test_gerrit_no_reviewer(self):
511 self._run_gerrit_upload_test(
512 [],
513 'desc\n\nBUG=\nChange-Id:123456789\n',
514 [])
515
ukai@chromium.orge8077812012-02-03 03:41:46 +0000516 def test_gerrit_reviewers_cmd_line(self):
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000517 self._run_gerrit_upload_test(
ukai@chromium.orge8077812012-02-03 03:41:46 +0000518 ['-r', 'foo@example.com'],
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000519 'desc\n\nBUG=\nChange-Id:123456789',
ukai@chromium.orge8077812012-02-03 03:41:46 +0000520 ['foo@example.com'])
521
522 def test_gerrit_reviewer_multiple(self):
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000523 self._run_gerrit_upload_test(
ukai@chromium.orge8077812012-02-03 03:41:46 +0000524 [],
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000525 'desc\nTBR=reviewer@example.com\nBUG=\nR=another@example.com\n'
526 'Change-Id:123456789\n',
ukai@chromium.orge8077812012-02-03 03:41:46 +0000527 ['reviewer@example.com', 'another@example.com'])
528
529
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000530 def test_config_gerrit_download_hook(self):
531 self.mock(git_cl, 'FindCodereviewSettingsFile', CodereviewSettingsFileMock)
532 def ParseCodereviewSettingsContent(content):
533 keyvals = {}
534 keyvals['CODE_REVIEW_SERVER'] = 'gerrit.chromium.org'
535 keyvals['GERRIT_HOST'] = 'gerrit.chromium.org'
536 keyvals['GERRIT_PORT'] = '29418'
537 return keyvals
538 self.mock(git_cl.gclient_utils, 'ParseCodereviewSettingsContent',
539 ParseCodereviewSettingsContent)
540 self.mock(git_cl.os, 'access', self._mocked_call)
541 self.mock(git_cl.os, 'chmod', self._mocked_call)
ukai@chromium.org91655502012-05-25 01:46:07 +0000542 src_dir = os.path.join(os.path.sep, 'usr', 'local', 'src')
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000543 def AbsPath(path):
ukai@chromium.org91655502012-05-25 01:46:07 +0000544 if not path.startswith(os.path.sep):
545 return os.path.join(src_dir, path)
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000546 return path
547 self.mock(git_cl.os.path, 'abspath', AbsPath)
ukai@chromium.org91655502012-05-25 01:46:07 +0000548 commit_msg_path = os.path.join(src_dir, '.git', 'hooks', 'commit-msg')
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000549 def Exists(path):
ukai@chromium.org91655502012-05-25 01:46:07 +0000550 if path == commit_msg_path:
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000551 return False
552 # others paths, such as /usr/share/locale/....
553 return True
554 self.mock(git_cl.os.path, 'exists', Exists)
joshua.lock@intel.com426f69b2012-08-02 23:41:49 +0000555 self.mock(git_cl, 'urlretrieve', self._mocked_call)
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000556 self.calls = [
557 ((['git', 'config', 'rietveld.server', 'gerrit.chromium.org'],), ''),
558 ((['git', 'config', '--unset-all', 'rietveld.cc'],), ''),
559 ((['git', 'config', '--unset-all', 'rietveld.tree-status-url'],), ''),
560 ((['git', 'config', '--unset-all', 'rietveld.viewvc-url'],), ''),
561 ((['git', 'config', 'gerrit.host', 'gerrit.chromium.org'],), ''),
562 ((['git', 'config', 'gerrit.port', '29418'],), ''),
563 # DownloadHooks(False)
564 ((['git', 'config', 'gerrit.host'],), 'gerrit.chromium.org'),
565 ((['git', 'config', 'rietveld.server'],), 'gerrit.chromium.org'),
566 ((['git', 'rev-parse', '--show-cdup'],), ''),
ukai@chromium.org91655502012-05-25 01:46:07 +0000567 ((commit_msg_path, os.X_OK,), False),
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000568 (('https://gerrit.chromium.org/tools/hooks/commit-msg',
ukai@chromium.org91655502012-05-25 01:46:07 +0000569 commit_msg_path,), ''),
570 ((commit_msg_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR,), ''),
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000571 # GetCodereviewSettingsInteractively
572 ((['git', 'config', 'rietveld.server'],), 'gerrit.chromium.org'),
573 (('Rietveld server (host[:port]) [https://gerrit.chromium.org]:',),
574 ''),
575 ((['git', 'config', 'rietveld.cc'],), ''),
576 (('CC list:',), ''),
577 ((['git', 'config', 'rietveld.tree-status-url'],), ''),
578 (('Tree status URL:',), ''),
579 ((['git', 'config', 'rietveld.viewvc-url'],), ''),
580 (('ViewVC URL:',), ''),
581 # DownloadHooks(True)
ukai@chromium.org91655502012-05-25 01:46:07 +0000582 ((commit_msg_path, os.X_OK,), True),
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000583 ]
584 git_cl.main(['config'])
585
586
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000587if __name__ == '__main__':
588 unittest.main()