blob: 23488ce516764f427b5ef59f10b4b5230d35646a [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.org4bac4b52012-11-27 20:33:52 +000072 self.mock(git_cl.rietveld, 'CachingRietveld', RietveldMock)
maruel@chromium.orgddd59412011-11-30 14:20:38 +000073 self.mock(git_cl.upload, 'RealMain', self.fail)
maruel@chromium.orgddd59412011-11-30 14:20:38 +000074 self.mock(git_cl.watchlists, 'Watchlists', WatchlistsMock)
75 # It's important to reset settings to not have inter-tests interference.
76 git_cl.settings = None
77
78 def tearDown(self):
79 if not self.has_failed():
80 self.assertEquals([], self.calls)
81 super(TestGitCl, self).tearDown()
82
maruel@chromium.org2e72bb12012-01-17 15:18:35 +000083 def _mocked_call(self, *args, **kwargs):
84 self.assertTrue(
85 self.calls,
86 '@%d Expected: <Missing> Actual: %r' % (self._calls_done, args))
87 expected_args, result = self.calls.pop(0)
88 self.assertEquals(
89 expected_args,
90 args,
91 '@%d Expected: %r Actual: %r' % (
92 self._calls_done, expected_args, args))
93 self._calls_done += 1
94 return result
95
maruel@chromium.orga3353652011-11-30 14:26:57 +000096 @classmethod
iannucci@chromium.org79540052012-10-19 23:15:26 +000097 def _upload_calls(cls, similarity, find_copies):
98 return (cls._git_base_calls(similarity, find_copies) +
99 cls._git_upload_calls())
maruel@chromium.orga3353652011-11-30 14:26:57 +0000100
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000101 @classmethod
102 def _git_base_calls(cls, similarity, find_copies):
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000103 if similarity is None:
104 similarity = '50'
105 similarity_call = ((['git', 'config', '--int', '--get',
106 'branch.master.git-cl-similarity'],), '')
107 else:
108 similarity_call = ((['git', 'config', '--int',
109 'branch.master.git-cl-similarity', similarity],), '')
iannucci@chromium.org79540052012-10-19 23:15:26 +0000110
111 if find_copies is None:
112 find_copies = True
113 find_copies_call = ((['git', 'config', '--int', '--get',
114 'branch.master.git-find-copies'],), '')
115 else:
116 val = str(int(find_copies))
117 find_copies_call = ((['git', 'config', '--int',
118 'branch.master.git-find-copies', val],), '')
119
120 if find_copies:
121 stat_call = ((['git', 'diff', '--no-ext-diff', '--stat',
122 '--find-copies-harder', '-l100000', '-C'+similarity,
sbc@chromium.org5e07e062013-02-28 23:55:44 +0000123 'fake_ancestor_sha', 'HEAD'],), '+dat')
iannucci@chromium.org79540052012-10-19 23:15:26 +0000124 else:
125 stat_call = ((['git', 'diff', '--no-ext-diff', '--stat',
sbc@chromium.org5e07e062013-02-28 23:55:44 +0000126 '-M'+similarity, 'fake_ancestor_sha', 'HEAD'],), '+dat')
iannucci@chromium.org79540052012-10-19 23:15:26 +0000127
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000128 return [
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,
ukai@chromium.org8ef7ab22012-11-28 04:24:52 +0000151 ((['git', 'config', 'gerrit.host'],), ''),
sbc@chromium.org5e07e062013-02-28 23:55:44 +0000152 ((['git', 'log', '--pretty=format:%s\n\n%b', 'fake_ancestor_sha..HEAD'],),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000153 'desc\n'),
maruel@chromium.orga3353652011-11-30 14:26:57 +0000154 ]
155
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000156 @classmethod
157 def _git_upload_calls(cls):
maruel@chromium.orga3353652011-11-30 14:26:57 +0000158 return [
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000159 ((['git', 'config', 'rietveld.cc'],), ''),
kalmard@homejinni.com6b0051e2012-04-03 15:45:08 +0000160 ((['git', 'config', 'branch.master.base-url'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000161 ((['git', 'config', '--get-regexp', '^svn-remote\\.'],),
162 (('', None), 0)),
163 ((['git', 'rev-parse', '--show-cdup'],), ''),
164 ((['git', 'svn', 'info'],), ''),
165 ((['git', 'config', 'branch.master.rietveldissue', '1'],), ''),
166 ((['git', 'config', 'branch.master.rietveldserver',
167 'https://codereview.example.com'],), ''),
168 ((['git', 'config', 'branch.master.rietveldpatchset', '2'],), ''),
rogerta@chromium.orgcaa16552013-03-18 20:45:05 +0000169 ((['git', 'rev-parse', 'HEAD'],), 'hash'),
170 ((['git', 'symbolic-ref', 'HEAD'],), 'hash'),
171 ((['git', 'config', 'branch.hash.last-upload-hash', 'hash'],), ''),
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000172 ]
173
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000174 @staticmethod
175 def _git_sanity_checks(diff_base, working_branch):
176 fake_ancestor = 'fake_ancestor'
177 fake_cl = 'fake_cl_for_patch'
178 return [
179 # Calls to verify branch point is ancestor
180 ((['git', 'rev-parse', '--verify', diff_base],), fake_ancestor),
181 ((['git', 'merge-base', fake_ancestor, 'HEAD'],), fake_ancestor),
182 ((['git', 'rev-list', '^' + fake_ancestor, 'HEAD'],), fake_cl),
183 # Mock a config miss (error code 1)
184 ((['git', 'config', 'gitcl.remotebranch'],), (('', None), 1)),
185 # Call to GetRemoteBranch()
186 ((['git', 'config', 'branch.%s.merge' % working_branch],),
187 'refs/heads/master'),
188 ((['git', 'config', 'branch.%s.remote' % working_branch],), 'origin'),
189 ((['git', 'rev-list', '^' + fake_ancestor,
190 'refs/remotes/origin/master'],), ''),
191 ]
192
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000193 @classmethod
194 def _dcommit_calls_1(cls):
195 return [
196 ((['git', 'config', '--get-regexp', '^svn-remote\\.'],),
197 ((('svn-remote.svn.url svn://svn.chromium.org/chrome\n'
198 'svn-remote.svn.fetch trunk/src:refs/remotes/origin/master'),
199 None),
200 0)),
201 ((['git', 'config', 'rietveld.server'],), 'codereview.example.com'),
202 ((['git', 'symbolic-ref', 'HEAD'],), 'refs/heads/working'),
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000203 ((['git', 'config', '--int', '--get',
204 'branch.working.git-cl-similarity'],), ''),
205 ((['git', 'symbolic-ref', 'HEAD'],), 'refs/heads/working'),
iannucci@chromium.org79540052012-10-19 23:15:26 +0000206 ((['git', 'config', '--int', '--get',
207 'branch.working.git-find-copies'],), ''),
208 ((['git', 'symbolic-ref', 'HEAD'],), 'refs/heads/working'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000209 ((['git', 'config', 'branch.working.merge'],), 'refs/heads/master'),
210 ((['git', 'config', 'branch.working.remote'],), 'origin'),
szager@chromium.org9bb85e22012-06-13 20:28:23 +0000211 ((['git', 'rev-list', '--merges',
szager@chromium.orge84b7542012-06-15 21:26:58 +0000212 '--grep=^SVN changes up to revision [0-9]*$',
szager@chromium.org9bb85e22012-06-13 20:28:23 +0000213 'refs/remotes/origin/master^!'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000214 ((['git', 'update-index', '--refresh', '-q'],), ''),
ukai@chromium.org259e4682012-10-25 07:36:33 +0000215 ((['git', 'diff-index', '--name-status', 'HEAD'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000216 ((['git', 'rev-list', '^refs/heads/working',
217 'refs/remotes/origin/master'],),
218 ''),
219 ((['git', 'log', '--grep=^git-svn-id:', '-1', '--pretty=format:%H'],),
220 '3fc18b62c4966193eb435baabe2d18a3810ec82e'),
221 ((['git', 'rev-list', '^3fc18b62c4966193eb435baabe2d18a3810ec82e',
222 'refs/remotes/origin/master'],), ''),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000223 ((['git', 'merge-base', 'refs/remotes/origin/master', 'HEAD'],),
224 'fake_ancestor_sha'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000225 ]
226
227 @classmethod
228 def _dcommit_calls_normal(cls):
229 return [
230 ((['git', 'rev-parse', '--show-cdup'],), ''),
231 ((['git', 'rev-parse', 'HEAD'],),
232 '00ff397798ea57439712ed7e04ab96e13969ef40'),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000233 ((['git', 'diff', '--name-status', '-r', 'fake_ancestor_sha...',
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000234 '.'],),
235 'M\tPRESUBMIT.py'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000236 ((['git', 'config', 'branch.working.rietveldissue'],), '12345'),
evan@chromium.org0af9b702012-02-11 00:42:16 +0000237 ((['git', 'config', 'branch.working.rietveldpatchset'],), '31137'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000238 ((['git', 'config', 'branch.working.rietveldserver'],),
239 'codereview.example.com'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000240 ((['git', 'config', 'user.email'],), 'author@example.com'),
241 ((['git', 'config', 'rietveld.tree-status-url'],), ''),
242 ]
243
244 @classmethod
245 def _dcommit_calls_bypassed(cls):
246 return [
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000247 ((['git', 'config', 'branch.working.rietveldissue'],), '12345'),
248 ((['git', 'config', 'branch.working.rietveldserver'],),
249 'codereview.example.com'),
250 (('GitClHooksBypassedCommit',
251 'Issue https://codereview.example.com/12345 bypassed hook when '
252 'committing'), None),
253 ]
254
255 @classmethod
256 def _dcommit_calls_3(cls):
257 return [
maruel@chromium.org49e3d802012-07-18 23:54:45 +0000258 ((['git', 'diff', '--no-ext-diff', '--stat', '--find-copies-harder',
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000259 '-l100000', '-C50', 'fake_ancestor_sha',
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000260 'refs/heads/working'],),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000261 (' PRESUBMIT.py | 2 +-\n'
262 ' 1 files changed, 1 insertions(+), 1 deletions(-)\n')),
263 (('About to commit; enter to confirm.',), None),
264 ((['git', 'show-ref', '--quiet', '--verify',
265 'refs/heads/git-cl-commit'],),
266 (('', None), 0)),
267 ((['git', 'branch', '-D', 'git-cl-commit'],), ''),
szager@chromium.org9bb85e22012-06-13 20:28:23 +0000268 ((['git', 'show-ref', '--quiet', '--verify',
269 'refs/heads/git-cl-cherry-pick'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000270 ((['git', 'rev-parse', '--show-cdup'],), '\n'),
271 ((['git', 'checkout', '-q', '-b', 'git-cl-commit'],), ''),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000272 ((['git', 'reset', '--soft', 'fake_ancestor_sha'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000273 ((['git', 'commit', '-m',
274 'Issue: 12345\n\nReview URL: https://codereview.example.com/12345'],),
275 ''),
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000276 ((['git', 'svn', 'dcommit', '-C50', '--no-rebase', '--rmdir'],),
277 (('', None), 0)),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000278 ((['git', 'checkout', '-q', 'working'],), ''),
279 ((['git', 'branch', '-D', 'git-cl-commit'],), ''),
280 ]
281
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000282 @staticmethod
iannucci@chromium.org79540052012-10-19 23:15:26 +0000283 def _cmd_line(description, args, similarity, find_copies):
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000284 """Returns the upload command line passed to upload.RealMain()."""
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000285 return [
286 'upload', '--assume_yes', '--server',
maruel@chromium.orgeb5edbc2012-01-16 17:03:28 +0000287 'https://codereview.example.com',
maruel@chromium.org71e12a92012-02-14 02:34:15 +0000288 '--message', description
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000289 ] + args + [
290 '--cc', 'joe@example.com',
iannucci@chromium.org79540052012-10-19 23:15:26 +0000291 '--git_similarity', similarity or '50'
292 ] + (['--git_no_find_copies'] if find_copies == False else []) + [
sbc@chromium.org5e07e062013-02-28 23:55:44 +0000293 'fake_ancestor_sha', 'HEAD'
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000294 ]
295
296 def _run_reviewer_test(
297 self,
298 upload_args,
299 expected_description,
300 returned_description,
301 final_description,
302 reviewers):
303 """Generic reviewer test framework."""
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000304 try:
305 similarity = upload_args[upload_args.index('--similarity')+1]
306 except ValueError:
307 similarity = None
iannucci@chromium.org79540052012-10-19 23:15:26 +0000308
309 if '--find-copies' in upload_args:
310 find_copies = True
311 elif '--no-find-copies' in upload_args:
312 find_copies = False
313 else:
314 find_copies = None
315
316 self.calls = self._upload_calls(similarity, find_copies)
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000317 def RunEditor(desc, _):
318 self.assertEquals(
319 '# Enter a description of the change.\n'
320 '# This will displayed on the codereview site.\n'
321 '# The first line will also be used as the subject of the review.\n' +
322 expected_description,
323 desc)
324 return returned_description
325 self.mock(git_cl.gclient_utils, 'RunEditor', RunEditor)
326 def check_upload(args):
iannucci@chromium.org79540052012-10-19 23:15:26 +0000327 cmd_line = self._cmd_line(final_description, reviewers, similarity,
328 find_copies)
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000329 self.assertEquals(cmd_line, args)
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000330 return 1, 2
331 self.mock(git_cl.upload, 'RealMain', check_upload)
332 git_cl.main(['upload'] + upload_args)
333
334 def test_no_reviewer(self):
335 self._run_reviewer_test(
336 [],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000337 'desc\n\nBUG=\n',
338 '# Blah blah comment.\ndesc\n\nBUG=\n',
339 'desc\n\nBUG=\n',
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000340 [])
341
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000342 def test_keep_similarity(self):
343 self._run_reviewer_test(
344 ['--similarity', '70'],
345 'desc\n\nBUG=\n',
346 '# Blah blah comment.\ndesc\n\nBUG=\n',
347 'desc\n\nBUG=\n',
348 [])
349
iannucci@chromium.org79540052012-10-19 23:15:26 +0000350 def test_keep_find_copies(self):
351 self._run_reviewer_test(
352 ['--no-find-copies'],
353 'desc\n\nBUG=\n',
354 '# Blah blah comment.\ndesc\n\nBUG=\n',
355 'desc\n\nBUG=\n',
356 [])
357
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000358 def test_reviewers_cmd_line(self):
359 # Reviewer is passed as-is
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000360 description = 'desc\n\nR=foo@example.com\nBUG=\n'
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000361 self._run_reviewer_test(
362 ['-r' 'foo@example.com'],
363 description,
364 '\n%s\n' % description,
365 description,
366 ['--reviewers', 'foo@example.com'])
367
368 def test_reviewer_tbr_overriden(self):
369 # Reviewer is overriden with TBR
370 # Also verifies the regexp work without a trailing LF
371 description = 'Foo Bar\nTBR=reviewer@example.com\n'
372 self._run_reviewer_test(
373 ['-r' 'foo@example.com'],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000374 'desc\n\nR=foo@example.com\nBUG=\n',
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000375 description.strip('\n'),
376 description,
377 ['--reviewers', 'reviewer@example.com'])
378
379 def test_reviewer_multiple(self):
380 # Handles multiple R= or TBR= lines.
381 description = (
382 'Foo Bar\nTBR=reviewer@example.com\nBUG=\nR=another@example.com\n')
383 self._run_reviewer_test(
384 [],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000385 'desc\n\nBUG=\n',
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000386 description,
387 description,
388 ['--reviewers', 'reviewer@example.com,another@example.com'])
389
maruel@chromium.orga3353652011-11-30 14:26:57 +0000390 def test_reviewer_send_mail(self):
391 # --send-mail can be used without -r if R= is used
392 description = 'Foo Bar\nR=reviewer@example.com\n'
393 self._run_reviewer_test(
394 ['--send-mail'],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000395 'desc\n\nBUG=\n',
maruel@chromium.orga3353652011-11-30 14:26:57 +0000396 description.strip('\n'),
397 description,
398 ['--reviewers', 'reviewer@example.com', '--send_mail'])
399
400 def test_reviewer_send_mail_no_rev(self):
401 # Fails without a reviewer.
402 class FileMock(object):
403 buf = StringIO.StringIO()
404 def write(self, content):
405 self.buf.write(content)
406
407 mock = FileMock()
408 try:
iannucci@chromium.org79540052012-10-19 23:15:26 +0000409 self.calls = self._git_base_calls(None, None)
maruel@chromium.orga3353652011-11-30 14:26:57 +0000410 def RunEditor(desc, _):
411 return desc
412 self.mock(git_cl.gclient_utils, 'RunEditor', RunEditor)
413 self.mock(sys, 'stderr', mock)
414 git_cl.main(['upload', '--send-mail'])
415 self.fail()
416 except SystemExit:
417 self.assertEquals(
418 'Must specify reviewers to send email.\n', mock.buf.getvalue())
419
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000420 def test_dcommit(self):
421 self.calls = (
422 self._dcommit_calls_1() +
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000423 self._git_sanity_checks('fake_ancestor_sha', 'working') +
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000424 self._dcommit_calls_normal() +
425 self._dcommit_calls_3())
426 git_cl.main(['dcommit'])
427
428 def test_dcommit_bypass_hooks(self):
429 self.calls = (
430 self._dcommit_calls_1() +
431 self._dcommit_calls_bypassed() +
432 self._dcommit_calls_3())
433 git_cl.main(['dcommit', '--bypass-hooks'])
434
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000435
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000436 @classmethod
437 def _gerrit_base_calls(cls):
ukai@chromium.orge8077812012-02-03 03:41:46 +0000438 return [
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000439 ((['git', 'config', 'rietveld.server'],), 'codereview.example.com'),
440 ((['git', 'symbolic-ref', 'HEAD'],), 'master'),
441 ((['git', 'config', '--int', '--get',
442 'branch.master.git-cl-similarity'],), ''),
iannucci@chromium.org79540052012-10-19 23:15:26 +0000443 ((['git', 'symbolic-ref', 'HEAD'],), 'master'),
444 ((['git', 'config', '--int', '--get',
445 'branch.master.git-find-copies'],), ''),
ukai@chromium.orge8077812012-02-03 03:41:46 +0000446 ((['git', 'update-index', '--refresh', '-q'],), ''),
ukai@chromium.org259e4682012-10-25 07:36:33 +0000447 ((['git', 'diff-index', '--name-status', 'HEAD'],), ''),
ukai@chromium.orge8077812012-02-03 03:41:46 +0000448 ((['git', 'symbolic-ref', 'HEAD'],), 'master'),
449 ((['git', 'config', 'branch.master.merge'],), 'master'),
450 ((['git', 'config', 'branch.master.remote'],), 'origin'),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000451 ((['git', 'merge-base', 'master', 'HEAD'],), 'fake_ancestor_sha'),
452 ] + cls._git_sanity_checks('fake_ancestor_sha', 'master') + [
ukai@chromium.orge8077812012-02-03 03:41:46 +0000453 ((['git', 'rev-parse', '--show-cdup'],), ''),
454 ((['git', 'rev-parse', 'HEAD'],), '12345'),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000455 ((['git', 'diff', '--name-status', '-r', 'fake_ancestor_sha...', '.'],),
ukai@chromium.orge8077812012-02-03 03:41:46 +0000456 'M\t.gitignore\n'),
ukai@chromium.orge8077812012-02-03 03:41:46 +0000457 ((['git', 'config', 'branch.master.rietveldissue'],), ''),
458 ((['git', 'config', 'branch.master.rietveldpatchset'],), ''),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000459 ((['git', 'log', '--pretty=format:%s%n%n%b', 'fake_ancestor_sha...'],),
460 'foo'),
ukai@chromium.orge8077812012-02-03 03:41:46 +0000461 ((['git', 'config', 'user.email'],), 'me@example.com'),
cmp@chromium.org5cf70222012-06-12 18:20:13 +0000462 ((['git', 'diff', '--no-ext-diff', '--stat', '--find-copies-harder',
sbc@chromium.org5e07e062013-02-28 23:55:44 +0000463 '-l100000', '-C50', 'fake_ancestor_sha', 'HEAD'],),
ukai@chromium.orge8077812012-02-03 03:41:46 +0000464 '+dat'),
465 ]
466
467 @staticmethod
468 def _gerrit_upload_calls(description, reviewers):
469 calls = [
ukai@chromium.org8ef7ab22012-11-28 04:24:52 +0000470 ((['git', 'config', 'gerrit.host'],), 'gerrit.example.com'),
sbc@chromium.org5e07e062013-02-28 23:55:44 +0000471 ((['git', 'log', '--pretty=format:%s\n\n%b',
472 'fake_ancestor_sha..HEAD'],),
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000473 description)
474 ]
475 if git_cl.CHANGE_ID not in description:
476 calls += [
sbc@chromium.org5e07e062013-02-28 23:55:44 +0000477 ((['git', 'log', '--pretty=format:%s\n\n%b',
478 'fake_ancestor_sha..HEAD'],),
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000479 description),
480 ((['git', 'commit', '--amend', '-m', description],),
481 ''),
sbc@chromium.org5e07e062013-02-28 23:55:44 +0000482 ((['git', 'log', '--pretty=format:%s\n\n%b',
483 'fake_ancestor_sha..HEAD'],),
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000484 description)
485 ]
486 calls += [
ukai@chromium.orge8077812012-02-03 03:41:46 +0000487 ((['git', 'config', 'rietveld.cc'],), '')
488 ]
ukai@chromium.org19bbfa22012-02-03 16:18:11 +0000489 receive_pack = '--receive-pack=git receive-pack '
ukai@chromium.orge8077812012-02-03 03:41:46 +0000490 receive_pack += '--cc=joe@example.com' # from watch list
491 if reviewers:
492 receive_pack += ' '
493 receive_pack += ' '.join(['--reviewer=' + email for email in reviewers])
ukai@chromium.org19bbfa22012-02-03 16:18:11 +0000494 receive_pack += ''
ukai@chromium.orge8077812012-02-03 03:41:46 +0000495 calls += [
496 ((['git', 'push', receive_pack, 'origin', 'HEAD:refs/for/master'],),
497 '')
498 ]
499 return calls
500
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000501 def _run_gerrit_upload_test(
ukai@chromium.orge8077812012-02-03 03:41:46 +0000502 self,
503 upload_args,
504 description,
505 reviewers):
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000506 """Generic gerrit upload test framework."""
ukai@chromium.orge8077812012-02-03 03:41:46 +0000507 self.calls = self._gerrit_base_calls()
508 self.calls += self._gerrit_upload_calls(description, reviewers)
509 git_cl.main(['upload'] + upload_args)
510
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000511 def test_gerrit_upload_without_change_id(self):
512 self._run_gerrit_upload_test(
ukai@chromium.orge8077812012-02-03 03:41:46 +0000513 [],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000514 'desc\n\nBUG=\n',
ukai@chromium.orge8077812012-02-03 03:41:46 +0000515 [])
516
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000517 def test_gerrit_no_reviewer(self):
518 self._run_gerrit_upload_test(
519 [],
520 'desc\n\nBUG=\nChange-Id:123456789\n',
521 [])
522
ukai@chromium.orge8077812012-02-03 03:41:46 +0000523 def test_gerrit_reviewers_cmd_line(self):
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000524 self._run_gerrit_upload_test(
ukai@chromium.orge8077812012-02-03 03:41:46 +0000525 ['-r', 'foo@example.com'],
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000526 'desc\n\nBUG=\nChange-Id:123456789',
ukai@chromium.orge8077812012-02-03 03:41:46 +0000527 ['foo@example.com'])
528
529 def test_gerrit_reviewer_multiple(self):
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000530 self._run_gerrit_upload_test(
ukai@chromium.orge8077812012-02-03 03:41:46 +0000531 [],
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000532 'desc\nTBR=reviewer@example.com\nBUG=\nR=another@example.com\n'
533 'Change-Id:123456789\n',
ukai@chromium.orge8077812012-02-03 03:41:46 +0000534 ['reviewer@example.com', 'another@example.com'])
535
536
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000537 def test_config_gerrit_download_hook(self):
538 self.mock(git_cl, 'FindCodereviewSettingsFile', CodereviewSettingsFileMock)
539 def ParseCodereviewSettingsContent(content):
540 keyvals = {}
541 keyvals['CODE_REVIEW_SERVER'] = 'gerrit.chromium.org'
542 keyvals['GERRIT_HOST'] = 'gerrit.chromium.org'
543 keyvals['GERRIT_PORT'] = '29418'
544 return keyvals
545 self.mock(git_cl.gclient_utils, 'ParseCodereviewSettingsContent',
546 ParseCodereviewSettingsContent)
547 self.mock(git_cl.os, 'access', self._mocked_call)
548 self.mock(git_cl.os, 'chmod', self._mocked_call)
ukai@chromium.org91655502012-05-25 01:46:07 +0000549 src_dir = os.path.join(os.path.sep, 'usr', 'local', 'src')
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000550 def AbsPath(path):
ukai@chromium.org91655502012-05-25 01:46:07 +0000551 if not path.startswith(os.path.sep):
552 return os.path.join(src_dir, path)
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000553 return path
554 self.mock(git_cl.os.path, 'abspath', AbsPath)
ukai@chromium.org91655502012-05-25 01:46:07 +0000555 commit_msg_path = os.path.join(src_dir, '.git', 'hooks', 'commit-msg')
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000556 def Exists(path):
ukai@chromium.org91655502012-05-25 01:46:07 +0000557 if path == commit_msg_path:
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000558 return False
559 # others paths, such as /usr/share/locale/....
560 return True
561 self.mock(git_cl.os.path, 'exists', Exists)
joshua.lock@intel.com426f69b2012-08-02 23:41:49 +0000562 self.mock(git_cl, 'urlretrieve', self._mocked_call)
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000563 self.calls = [
564 ((['git', 'config', 'rietveld.server', 'gerrit.chromium.org'],), ''),
565 ((['git', 'config', '--unset-all', 'rietveld.cc'],), ''),
566 ((['git', 'config', '--unset-all', 'rietveld.tree-status-url'],), ''),
567 ((['git', 'config', '--unset-all', 'rietveld.viewvc-url'],), ''),
568 ((['git', 'config', 'gerrit.host', 'gerrit.chromium.org'],), ''),
569 ((['git', 'config', 'gerrit.port', '29418'],), ''),
570 # DownloadHooks(False)
571 ((['git', 'config', 'gerrit.host'],), 'gerrit.chromium.org'),
572 ((['git', 'config', 'rietveld.server'],), 'gerrit.chromium.org'),
573 ((['git', 'rev-parse', '--show-cdup'],), ''),
ukai@chromium.org91655502012-05-25 01:46:07 +0000574 ((commit_msg_path, os.X_OK,), False),
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000575 (('https://gerrit.chromium.org/tools/hooks/commit-msg',
ukai@chromium.org91655502012-05-25 01:46:07 +0000576 commit_msg_path,), ''),
577 ((commit_msg_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR,), ''),
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000578 # GetCodereviewSettingsInteractively
579 ((['git', 'config', 'rietveld.server'],), 'gerrit.chromium.org'),
580 (('Rietveld server (host[:port]) [https://gerrit.chromium.org]:',),
581 ''),
582 ((['git', 'config', 'rietveld.cc'],), ''),
583 (('CC list:',), ''),
584 ((['git', 'config', 'rietveld.tree-status-url'],), ''),
585 (('Tree status URL:',), ''),
586 ((['git', 'config', 'rietveld.viewvc-url'],), ''),
587 (('ViewVC URL:',), ''),
588 # DownloadHooks(True)
ukai@chromium.org91655502012-05-25 01:46:07 +0000589 ((commit_msg_path, os.X_OK,), True),
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000590 ]
591 git_cl.main(['config'])
592
593
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000594if __name__ == '__main__':
595 unittest.main()