blob: d8ee31722293ef8a388a5dacbe76f9fd94d9235b [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'],), ''),
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000169 ]
170
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000171 @staticmethod
172 def _git_sanity_checks(diff_base, working_branch):
173 fake_ancestor = 'fake_ancestor'
174 fake_cl = 'fake_cl_for_patch'
175 return [
176 # Calls to verify branch point is ancestor
177 ((['git', 'rev-parse', '--verify', diff_base],), fake_ancestor),
178 ((['git', 'merge-base', fake_ancestor, 'HEAD'],), fake_ancestor),
179 ((['git', 'rev-list', '^' + fake_ancestor, 'HEAD'],), fake_cl),
180 # Mock a config miss (error code 1)
181 ((['git', 'config', 'gitcl.remotebranch'],), (('', None), 1)),
182 # Call to GetRemoteBranch()
183 ((['git', 'config', 'branch.%s.merge' % working_branch],),
184 'refs/heads/master'),
185 ((['git', 'config', 'branch.%s.remote' % working_branch],), 'origin'),
186 ((['git', 'rev-list', '^' + fake_ancestor,
187 'refs/remotes/origin/master'],), ''),
188 ]
189
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000190 @classmethod
191 def _dcommit_calls_1(cls):
192 return [
193 ((['git', 'config', '--get-regexp', '^svn-remote\\.'],),
194 ((('svn-remote.svn.url svn://svn.chromium.org/chrome\n'
195 'svn-remote.svn.fetch trunk/src:refs/remotes/origin/master'),
196 None),
197 0)),
198 ((['git', 'config', 'rietveld.server'],), 'codereview.example.com'),
199 ((['git', 'symbolic-ref', 'HEAD'],), 'refs/heads/working'),
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000200 ((['git', 'config', '--int', '--get',
201 'branch.working.git-cl-similarity'],), ''),
202 ((['git', 'symbolic-ref', 'HEAD'],), 'refs/heads/working'),
iannucci@chromium.org79540052012-10-19 23:15:26 +0000203 ((['git', 'config', '--int', '--get',
204 'branch.working.git-find-copies'],), ''),
205 ((['git', 'symbolic-ref', 'HEAD'],), 'refs/heads/working'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000206 ((['git', 'config', 'branch.working.merge'],), 'refs/heads/master'),
207 ((['git', 'config', 'branch.working.remote'],), 'origin'),
szager@chromium.org9bb85e22012-06-13 20:28:23 +0000208 ((['git', 'rev-list', '--merges',
szager@chromium.orge84b7542012-06-15 21:26:58 +0000209 '--grep=^SVN changes up to revision [0-9]*$',
szager@chromium.org9bb85e22012-06-13 20:28:23 +0000210 'refs/remotes/origin/master^!'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000211 ((['git', 'update-index', '--refresh', '-q'],), ''),
ukai@chromium.org259e4682012-10-25 07:36:33 +0000212 ((['git', 'diff-index', '--name-status', 'HEAD'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000213 ((['git', 'rev-list', '^refs/heads/working',
214 'refs/remotes/origin/master'],),
215 ''),
216 ((['git', 'log', '--grep=^git-svn-id:', '-1', '--pretty=format:%H'],),
217 '3fc18b62c4966193eb435baabe2d18a3810ec82e'),
218 ((['git', 'rev-list', '^3fc18b62c4966193eb435baabe2d18a3810ec82e',
219 'refs/remotes/origin/master'],), ''),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000220 ((['git', 'merge-base', 'refs/remotes/origin/master', 'HEAD'],),
221 'fake_ancestor_sha'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000222 ]
223
224 @classmethod
225 def _dcommit_calls_normal(cls):
226 return [
227 ((['git', 'rev-parse', '--show-cdup'],), ''),
228 ((['git', 'rev-parse', 'HEAD'],),
229 '00ff397798ea57439712ed7e04ab96e13969ef40'),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000230 ((['git', 'diff', '--name-status', '-r', 'fake_ancestor_sha...',
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000231 '.'],),
232 'M\tPRESUBMIT.py'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000233 ((['git', 'config', 'branch.working.rietveldissue'],), '12345'),
evan@chromium.org0af9b702012-02-11 00:42:16 +0000234 ((['git', 'config', 'branch.working.rietveldpatchset'],), '31137'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000235 ((['git', 'config', 'branch.working.rietveldserver'],),
236 'codereview.example.com'),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000237 ((['git', 'config', 'user.email'],), 'author@example.com'),
238 ((['git', 'config', 'rietveld.tree-status-url'],), ''),
239 ]
240
241 @classmethod
242 def _dcommit_calls_bypassed(cls):
243 return [
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000244 ((['git', 'config', 'branch.working.rietveldissue'],), '12345'),
245 ((['git', 'config', 'branch.working.rietveldserver'],),
246 'codereview.example.com'),
247 (('GitClHooksBypassedCommit',
248 'Issue https://codereview.example.com/12345 bypassed hook when '
249 'committing'), None),
250 ]
251
252 @classmethod
253 def _dcommit_calls_3(cls):
254 return [
maruel@chromium.org49e3d802012-07-18 23:54:45 +0000255 ((['git', 'diff', '--no-ext-diff', '--stat', '--find-copies-harder',
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000256 '-l100000', '-C50', 'fake_ancestor_sha',
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000257 'refs/heads/working'],),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000258 (' PRESUBMIT.py | 2 +-\n'
259 ' 1 files changed, 1 insertions(+), 1 deletions(-)\n')),
260 (('About to commit; enter to confirm.',), None),
261 ((['git', 'show-ref', '--quiet', '--verify',
262 'refs/heads/git-cl-commit'],),
263 (('', None), 0)),
264 ((['git', 'branch', '-D', 'git-cl-commit'],), ''),
szager@chromium.org9bb85e22012-06-13 20:28:23 +0000265 ((['git', 'show-ref', '--quiet', '--verify',
266 'refs/heads/git-cl-cherry-pick'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000267 ((['git', 'rev-parse', '--show-cdup'],), '\n'),
268 ((['git', 'checkout', '-q', '-b', 'git-cl-commit'],), ''),
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000269 ((['git', 'reset', '--soft', 'fake_ancestor_sha'],), ''),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000270 ((['git', 'commit', '-m',
271 'Issue: 12345\n\nReview URL: https://codereview.example.com/12345'],),
272 ''),
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000273 ((['git', 'svn', 'dcommit', '-C50', '--no-rebase', '--rmdir'],),
274 (('', None), 0)),
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000275 ((['git', 'checkout', '-q', 'working'],), ''),
276 ((['git', 'branch', '-D', 'git-cl-commit'],), ''),
277 ]
278
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000279 @staticmethod
iannucci@chromium.org79540052012-10-19 23:15:26 +0000280 def _cmd_line(description, args, similarity, find_copies):
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000281 """Returns the upload command line passed to upload.RealMain()."""
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000282 return [
283 'upload', '--assume_yes', '--server',
maruel@chromium.orgeb5edbc2012-01-16 17:03:28 +0000284 'https://codereview.example.com',
maruel@chromium.org71e12a92012-02-14 02:34:15 +0000285 '--message', description
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000286 ] + args + [
287 '--cc', 'joe@example.com',
iannucci@chromium.org79540052012-10-19 23:15:26 +0000288 '--git_similarity', similarity or '50'
289 ] + (['--git_no_find_copies'] if find_copies == False else []) + [
sbc@chromium.org5e07e062013-02-28 23:55:44 +0000290 'fake_ancestor_sha', 'HEAD'
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000291 ]
292
293 def _run_reviewer_test(
294 self,
295 upload_args,
296 expected_description,
297 returned_description,
298 final_description,
299 reviewers):
300 """Generic reviewer test framework."""
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000301 try:
302 similarity = upload_args[upload_args.index('--similarity')+1]
303 except ValueError:
304 similarity = None
iannucci@chromium.org79540052012-10-19 23:15:26 +0000305
306 if '--find-copies' in upload_args:
307 find_copies = True
308 elif '--no-find-copies' in upload_args:
309 find_copies = False
310 else:
311 find_copies = None
312
313 self.calls = self._upload_calls(similarity, find_copies)
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000314 def RunEditor(desc, _):
315 self.assertEquals(
316 '# Enter a description of the change.\n'
317 '# This will displayed on the codereview site.\n'
318 '# The first line will also be used as the subject of the review.\n' +
319 expected_description,
320 desc)
321 return returned_description
322 self.mock(git_cl.gclient_utils, 'RunEditor', RunEditor)
323 def check_upload(args):
iannucci@chromium.org79540052012-10-19 23:15:26 +0000324 cmd_line = self._cmd_line(final_description, reviewers, similarity,
325 find_copies)
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000326 self.assertEquals(cmd_line, args)
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000327 return 1, 2
328 self.mock(git_cl.upload, 'RealMain', check_upload)
329 git_cl.main(['upload'] + upload_args)
330
331 def test_no_reviewer(self):
332 self._run_reviewer_test(
333 [],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000334 'desc\n\nBUG=\n',
335 '# Blah blah comment.\ndesc\n\nBUG=\n',
336 'desc\n\nBUG=\n',
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000337 [])
338
iannucci@chromium.org53937ba2012-10-02 18:20:43 +0000339 def test_keep_similarity(self):
340 self._run_reviewer_test(
341 ['--similarity', '70'],
342 'desc\n\nBUG=\n',
343 '# Blah blah comment.\ndesc\n\nBUG=\n',
344 'desc\n\nBUG=\n',
345 [])
346
iannucci@chromium.org79540052012-10-19 23:15:26 +0000347 def test_keep_find_copies(self):
348 self._run_reviewer_test(
349 ['--no-find-copies'],
350 'desc\n\nBUG=\n',
351 '# Blah blah comment.\ndesc\n\nBUG=\n',
352 'desc\n\nBUG=\n',
353 [])
354
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000355 def test_reviewers_cmd_line(self):
356 # Reviewer is passed as-is
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000357 description = 'desc\n\nR=foo@example.com\nBUG=\n'
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000358 self._run_reviewer_test(
359 ['-r' 'foo@example.com'],
360 description,
361 '\n%s\n' % description,
362 description,
363 ['--reviewers', 'foo@example.com'])
364
365 def test_reviewer_tbr_overriden(self):
366 # Reviewer is overriden with TBR
367 # Also verifies the regexp work without a trailing LF
368 description = 'Foo Bar\nTBR=reviewer@example.com\n'
369 self._run_reviewer_test(
370 ['-r' 'foo@example.com'],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000371 'desc\n\nR=foo@example.com\nBUG=\n',
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000372 description.strip('\n'),
373 description,
374 ['--reviewers', 'reviewer@example.com'])
375
376 def test_reviewer_multiple(self):
377 # Handles multiple R= or TBR= lines.
378 description = (
379 'Foo Bar\nTBR=reviewer@example.com\nBUG=\nR=another@example.com\n')
380 self._run_reviewer_test(
381 [],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000382 'desc\n\nBUG=\n',
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000383 description,
384 description,
385 ['--reviewers', 'reviewer@example.com,another@example.com'])
386
maruel@chromium.orga3353652011-11-30 14:26:57 +0000387 def test_reviewer_send_mail(self):
388 # --send-mail can be used without -r if R= is used
389 description = 'Foo Bar\nR=reviewer@example.com\n'
390 self._run_reviewer_test(
391 ['--send-mail'],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000392 'desc\n\nBUG=\n',
maruel@chromium.orga3353652011-11-30 14:26:57 +0000393 description.strip('\n'),
394 description,
395 ['--reviewers', 'reviewer@example.com', '--send_mail'])
396
397 def test_reviewer_send_mail_no_rev(self):
398 # Fails without a reviewer.
399 class FileMock(object):
400 buf = StringIO.StringIO()
401 def write(self, content):
402 self.buf.write(content)
403
404 mock = FileMock()
405 try:
iannucci@chromium.org79540052012-10-19 23:15:26 +0000406 self.calls = self._git_base_calls(None, None)
maruel@chromium.orga3353652011-11-30 14:26:57 +0000407 def RunEditor(desc, _):
408 return desc
409 self.mock(git_cl.gclient_utils, 'RunEditor', RunEditor)
410 self.mock(sys, 'stderr', mock)
411 git_cl.main(['upload', '--send-mail'])
412 self.fail()
413 except SystemExit:
414 self.assertEquals(
415 'Must specify reviewers to send email.\n', mock.buf.getvalue())
416
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000417 def test_dcommit(self):
418 self.calls = (
419 self._dcommit_calls_1() +
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000420 self._git_sanity_checks('fake_ancestor_sha', 'working') +
maruel@chromium.org2e72bb12012-01-17 15:18:35 +0000421 self._dcommit_calls_normal() +
422 self._dcommit_calls_3())
423 git_cl.main(['dcommit'])
424
425 def test_dcommit_bypass_hooks(self):
426 self.calls = (
427 self._dcommit_calls_1() +
428 self._dcommit_calls_bypassed() +
429 self._dcommit_calls_3())
430 git_cl.main(['dcommit', '--bypass-hooks'])
431
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000432
ilevy@chromium.org0f58fa82012-11-05 01:45:20 +0000433 @classmethod
434 def _gerrit_base_calls(cls):
ukai@chromium.orge8077812012-02-03 03:41:46 +0000435 return [
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',
sbc@chromium.org5e07e062013-02-28 23:55:44 +0000460 '-l100000', '-C50', 'fake_ancestor_sha', 'HEAD'],),
ukai@chromium.orge8077812012-02-03 03:41:46 +0000461 '+dat'),
462 ]
463
464 @staticmethod
465 def _gerrit_upload_calls(description, reviewers):
466 calls = [
ukai@chromium.org8ef7ab22012-11-28 04:24:52 +0000467 ((['git', 'config', 'gerrit.host'],), 'gerrit.example.com'),
sbc@chromium.org5e07e062013-02-28 23:55:44 +0000468 ((['git', 'log', '--pretty=format:%s\n\n%b',
469 'fake_ancestor_sha..HEAD'],),
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000470 description)
471 ]
472 if git_cl.CHANGE_ID not in description:
473 calls += [
sbc@chromium.org5e07e062013-02-28 23:55:44 +0000474 ((['git', 'log', '--pretty=format:%s\n\n%b',
475 'fake_ancestor_sha..HEAD'],),
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000476 description),
477 ((['git', 'commit', '--amend', '-m', description],),
478 ''),
sbc@chromium.org5e07e062013-02-28 23:55:44 +0000479 ((['git', 'log', '--pretty=format:%s\n\n%b',
480 'fake_ancestor_sha..HEAD'],),
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000481 description)
482 ]
483 calls += [
ukai@chromium.orge8077812012-02-03 03:41:46 +0000484 ((['git', 'config', 'rietveld.cc'],), '')
485 ]
ukai@chromium.org19bbfa22012-02-03 16:18:11 +0000486 receive_pack = '--receive-pack=git receive-pack '
ukai@chromium.orge8077812012-02-03 03:41:46 +0000487 receive_pack += '--cc=joe@example.com' # from watch list
488 if reviewers:
489 receive_pack += ' '
490 receive_pack += ' '.join(['--reviewer=' + email for email in reviewers])
ukai@chromium.org19bbfa22012-02-03 16:18:11 +0000491 receive_pack += ''
ukai@chromium.orge8077812012-02-03 03:41:46 +0000492 calls += [
493 ((['git', 'push', receive_pack, 'origin', 'HEAD:refs/for/master'],),
494 '')
495 ]
496 return calls
497
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000498 def _run_gerrit_upload_test(
ukai@chromium.orge8077812012-02-03 03:41:46 +0000499 self,
500 upload_args,
501 description,
502 reviewers):
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000503 """Generic gerrit upload test framework."""
ukai@chromium.orge8077812012-02-03 03:41:46 +0000504 self.calls = self._gerrit_base_calls()
505 self.calls += self._gerrit_upload_calls(description, reviewers)
506 git_cl.main(['upload'] + upload_args)
507
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000508 def test_gerrit_upload_without_change_id(self):
509 self._run_gerrit_upload_test(
ukai@chromium.orge8077812012-02-03 03:41:46 +0000510 [],
jamesr@chromium.org35d1a842012-07-27 00:20:43 +0000511 'desc\n\nBUG=\n',
ukai@chromium.orge8077812012-02-03 03:41:46 +0000512 [])
513
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000514 def test_gerrit_no_reviewer(self):
515 self._run_gerrit_upload_test(
516 [],
517 'desc\n\nBUG=\nChange-Id:123456789\n',
518 [])
519
ukai@chromium.orge8077812012-02-03 03:41:46 +0000520 def test_gerrit_reviewers_cmd_line(self):
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000521 self._run_gerrit_upload_test(
ukai@chromium.orge8077812012-02-03 03:41:46 +0000522 ['-r', 'foo@example.com'],
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000523 'desc\n\nBUG=\nChange-Id:123456789',
ukai@chromium.orge8077812012-02-03 03:41:46 +0000524 ['foo@example.com'])
525
526 def test_gerrit_reviewer_multiple(self):
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000527 self._run_gerrit_upload_test(
ukai@chromium.orge8077812012-02-03 03:41:46 +0000528 [],
sivachandra@chromium.orgaebe87f2012-10-22 20:34:21 +0000529 'desc\nTBR=reviewer@example.com\nBUG=\nR=another@example.com\n'
530 'Change-Id:123456789\n',
ukai@chromium.orge8077812012-02-03 03:41:46 +0000531 ['reviewer@example.com', 'another@example.com'])
532
533
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000534 def test_config_gerrit_download_hook(self):
535 self.mock(git_cl, 'FindCodereviewSettingsFile', CodereviewSettingsFileMock)
536 def ParseCodereviewSettingsContent(content):
537 keyvals = {}
538 keyvals['CODE_REVIEW_SERVER'] = 'gerrit.chromium.org'
539 keyvals['GERRIT_HOST'] = 'gerrit.chromium.org'
540 keyvals['GERRIT_PORT'] = '29418'
541 return keyvals
542 self.mock(git_cl.gclient_utils, 'ParseCodereviewSettingsContent',
543 ParseCodereviewSettingsContent)
544 self.mock(git_cl.os, 'access', self._mocked_call)
545 self.mock(git_cl.os, 'chmod', self._mocked_call)
ukai@chromium.org91655502012-05-25 01:46:07 +0000546 src_dir = os.path.join(os.path.sep, 'usr', 'local', 'src')
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000547 def AbsPath(path):
ukai@chromium.org91655502012-05-25 01:46:07 +0000548 if not path.startswith(os.path.sep):
549 return os.path.join(src_dir, path)
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000550 return path
551 self.mock(git_cl.os.path, 'abspath', AbsPath)
ukai@chromium.org91655502012-05-25 01:46:07 +0000552 commit_msg_path = os.path.join(src_dir, '.git', 'hooks', 'commit-msg')
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000553 def Exists(path):
ukai@chromium.org91655502012-05-25 01:46:07 +0000554 if path == commit_msg_path:
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000555 return False
556 # others paths, such as /usr/share/locale/....
557 return True
558 self.mock(git_cl.os.path, 'exists', Exists)
joshua.lock@intel.com426f69b2012-08-02 23:41:49 +0000559 self.mock(git_cl, 'urlretrieve', self._mocked_call)
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000560 self.calls = [
561 ((['git', 'config', 'rietveld.server', 'gerrit.chromium.org'],), ''),
562 ((['git', 'config', '--unset-all', 'rietveld.cc'],), ''),
563 ((['git', 'config', '--unset-all', 'rietveld.tree-status-url'],), ''),
564 ((['git', 'config', '--unset-all', 'rietveld.viewvc-url'],), ''),
565 ((['git', 'config', 'gerrit.host', 'gerrit.chromium.org'],), ''),
566 ((['git', 'config', 'gerrit.port', '29418'],), ''),
567 # DownloadHooks(False)
568 ((['git', 'config', 'gerrit.host'],), 'gerrit.chromium.org'),
569 ((['git', 'config', 'rietveld.server'],), 'gerrit.chromium.org'),
570 ((['git', 'rev-parse', '--show-cdup'],), ''),
ukai@chromium.org91655502012-05-25 01:46:07 +0000571 ((commit_msg_path, os.X_OK,), False),
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000572 (('https://gerrit.chromium.org/tools/hooks/commit-msg',
ukai@chromium.org91655502012-05-25 01:46:07 +0000573 commit_msg_path,), ''),
574 ((commit_msg_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR,), ''),
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000575 # GetCodereviewSettingsInteractively
576 ((['git', 'config', 'rietveld.server'],), 'gerrit.chromium.org'),
577 (('Rietveld server (host[:port]) [https://gerrit.chromium.org]:',),
578 ''),
579 ((['git', 'config', 'rietveld.cc'],), ''),
580 (('CC list:',), ''),
581 ((['git', 'config', 'rietveld.tree-status-url'],), ''),
582 (('Tree status URL:',), ''),
583 ((['git', 'config', 'rietveld.viewvc-url'],), ''),
584 (('ViewVC URL:',), ''),
585 # DownloadHooks(True)
ukai@chromium.org91655502012-05-25 01:46:07 +0000586 ((commit_msg_path, os.X_OK,), True),
ukai@chromium.org78c4b982012-02-14 02:20:26 +0000587 ]
588 git_cl.main(['config'])
589
590
maruel@chromium.orgddd59412011-11-30 14:20:38 +0000591if __name__ == '__main__':
592 unittest.main()