Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(425)

Side by Side Diff: tests/git_cl_test.py

Issue 1882583003: Gerrit git cl upload: add check for missing credentials. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@R250
Patch Set: argh,fix Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « git_cl.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Unit tests for git_cl.py.""" 6 """Unit tests for git_cl.py."""
7 7
8 import os 8 import os
9 import StringIO 9 import StringIO
10 import stat 10 import stat
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 "GERRIT_HOST: True\n") 67 "GERRIT_HOST: True\n")
68 68
69 69
70 class AuthenticatorMock(object): 70 class AuthenticatorMock(object):
71 def __init__(self, *_args): 71 def __init__(self, *_args):
72 pass 72 pass
73 def has_cached_credentials(self): 73 def has_cached_credentials(self):
74 return True 74 return True
75 75
76 76
77 def CookiesAuthenticatorMockFactory(hosts_with_creds=None, same_cookie=False):
78 """Use to mock Gerrit/Git credentials from ~/.netrc or ~/.gitcookies.
79
80 Usage:
81 >>> self.mock(git_cl.gerrit_util, "CookiesAuthenticator",
82 CookiesAuthenticatorMockFactory({'host1': 'cookie1'}))
83
84 OR
85 >>> self.mock(git_cl.gerrit_util, "CookiesAuthenticator",
86 CookiesAuthenticatorMockFactory(cookie='cookie'))
87 """
88 class CookiesAuthenticatorMock(git_cl.gerrit_util.CookiesAuthenticator):
89 def __init__(self): # pylint: disable=W0231
90 # Intentionally not calling super() because it reads actual cookie files.
91 pass
92 @classmethod
93 def get_gitcookies_path(cls):
94 return '~/.gitcookies'
95 @classmethod
96 def get_netrc_path(cls):
97 return '~/.netrc'
98 def get_auth_header(self, host):
99 if same_cookie:
100 return same_cookie
101 return (hosts_with_creds or {}).get(host)
102 return CookiesAuthenticatorMock
103
104
77 class TestGitClBasic(unittest.TestCase): 105 class TestGitClBasic(unittest.TestCase):
78 def _test_ParseIssueUrl(self, func, url, issue, patchset, hostname, fail): 106 def _test_ParseIssueUrl(self, func, url, issue, patchset, hostname, fail):
79 parsed = urlparse.urlparse(url) 107 parsed = urlparse.urlparse(url)
80 result = func(parsed) 108 result = func(parsed)
81 if fail: 109 if fail:
82 self.assertIsNone(result) 110 self.assertIsNone(result)
83 return None 111 return None
84 self.assertIsNotNone(result) 112 self.assertIsNotNone(result)
85 self.assertEqual(result.issue, issue) 113 self.assertEqual(result.issue, issue)
86 self.assertEqual(result.patchset, patchset) 114 self.assertEqual(result.patchset, patchset)
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 self._mocked_call(['get_or_create_merge_base']+list(a)))) 212 self._mocked_call(['get_or_create_merge_base']+list(a))))
185 self.mock(git_cl, 'BranchExists', lambda _: True) 213 self.mock(git_cl, 'BranchExists', lambda _: True)
186 self.mock(git_cl, 'FindCodereviewSettingsFile', lambda: '') 214 self.mock(git_cl, 'FindCodereviewSettingsFile', lambda: '')
187 self.mock(git_cl, 'ask_for_data', self._mocked_call) 215 self.mock(git_cl, 'ask_for_data', self._mocked_call)
188 self.mock(git_cl.presubmit_support, 'DoPresubmitChecks', PresubmitMock) 216 self.mock(git_cl.presubmit_support, 'DoPresubmitChecks', PresubmitMock)
189 self.mock(git_cl.rietveld, 'Rietveld', RietveldMock) 217 self.mock(git_cl.rietveld, 'Rietveld', RietveldMock)
190 self.mock(git_cl.rietveld, 'CachingRietveld', RietveldMock) 218 self.mock(git_cl.rietveld, 'CachingRietveld', RietveldMock)
191 self.mock(git_cl.upload, 'RealMain', self.fail) 219 self.mock(git_cl.upload, 'RealMain', self.fail)
192 self.mock(git_cl.watchlists, 'Watchlists', WatchlistsMock) 220 self.mock(git_cl.watchlists, 'Watchlists', WatchlistsMock)
193 self.mock(git_cl.auth, 'get_authenticator_for_host', AuthenticatorMock) 221 self.mock(git_cl.auth, 'get_authenticator_for_host', AuthenticatorMock)
222 self.mock(git_cl.gerrit_util.GceAuthenticator, 'is_gce',
223 classmethod(lambda _: False))
194 # It's important to reset settings to not have inter-tests interference. 224 # It's important to reset settings to not have inter-tests interference.
195 git_cl.settings = None 225 git_cl.settings = None
196 226
197 227
198 def tearDown(self): 228 def tearDown(self):
199 try: 229 try:
200 # Note: has_failed returns True if at least 1 test ran so far, current 230 # Note: has_failed returns True if at least 1 test ran so far, current
201 # included, has failed. That means current test may have actually ran 231 # included, has failed. That means current test may have actually ran
202 # fine, and the check for no leftover calls would be skipped. 232 # fine, and the check for no leftover calls would be skipped.
203 if not self.has_failed(): 233 if not self.has_failed():
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 def _git_post_upload_calls(cls): 369 def _git_post_upload_calls(cls):
340 return [ 370 return [
341 ((['git', 'rev-parse', 'HEAD'],), 'hash'), 371 ((['git', 'rev-parse', 'HEAD'],), 'hash'),
342 ((['git', 'symbolic-ref', 'HEAD'],), 'hash'), 372 ((['git', 'symbolic-ref', 'HEAD'],), 'hash'),
343 ((['git', 373 ((['git',
344 'config', 'branch.hash.last-upload-hash', 'hash'],), ''), 374 'config', 'branch.hash.last-upload-hash', 'hash'],), ''),
345 ((['git', 'config', 'rietveld.run-post-upload-hook'],), ''), 375 ((['git', 'config', 'rietveld.run-post-upload-hook'],), ''),
346 ] 376 ]
347 377
348 @staticmethod 378 @staticmethod
349 def _git_sanity_checks(diff_base, working_branch): 379 def _git_sanity_checks(diff_base, working_branch, get_remote_branch=True):
350 fake_ancestor = 'fake_ancestor' 380 fake_ancestor = 'fake_ancestor'
351 fake_cl = 'fake_cl_for_patch' 381 fake_cl = 'fake_cl_for_patch'
352 return [ 382 return [
353 # Calls to verify branch point is ancestor
354 ((['git', 383 ((['git',
355 'rev-parse', '--verify', diff_base],), fake_ancestor), 384 'rev-parse', '--verify', diff_base],), fake_ancestor),
356 ((['git', 385 ((['git',
357 'merge-base', fake_ancestor, 'HEAD'],), fake_ancestor), 386 'merge-base', fake_ancestor, 'HEAD'],), fake_ancestor),
358 ((['git', 387 ((['git',
359 'rev-list', '^' + fake_ancestor, 'HEAD'],), fake_cl), 388 'rev-list', '^' + fake_ancestor, 'HEAD'],), fake_cl),
360 # Mock a config miss (error code 1) 389 # Mock a config miss (error code 1)
361 ((['git', 390 ((['git',
362 'config', 'gitcl.remotebranch'],), (('', None), 1)), 391 'config', 'gitcl.remotebranch'],), (('', None), 1)),
392 ] + ([
363 # Call to GetRemoteBranch() 393 # Call to GetRemoteBranch()
364 ((['git', 394 ((['git',
365 'config', 'branch.%s.merge' % working_branch],), 395 'config', 'branch.%s.merge' % working_branch],),
366 'refs/heads/master'), 396 'refs/heads/master'),
367 ((['git', 397 ((['git',
368 'config', 'branch.%s.remote' % working_branch],), 'origin'), 398 'config', 'branch.%s.remote' % working_branch],), 'origin'),
399 ] if get_remote_branch else []) + [
369 ((['git', 'rev-list', '^' + fake_ancestor, 400 ((['git', 'rev-list', '^' + fake_ancestor,
370 'refs/remotes/origin/master'],), ''), 401 'refs/remotes/origin/master'],), ''),
371 ] 402 ]
372 403
373 @classmethod 404 @classmethod
374 def _dcommit_calls_1(cls): 405 def _dcommit_calls_1(cls):
375 return [ 406 return [
376 ((['git', 'config', 'rietveld.autoupdate'],), 407 ((['git', 'config', 'rietveld.autoupdate'],),
377 ''), 408 ''),
378 ((['git', 'config', 'rietveld.pending-ref-prefix'],), 409 ((['git', 'config', 'rietveld.pending-ref-prefix'],),
379 ''), 410 ''),
380 ((['git', 411 ((['git',
381 'config', '--local', '--get-regexp', '^svn-remote\\.'],), 412 'config', '--local', '--get-regexp', '^svn-remote\\.'],),
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
638 669
639 def test_dcommit_bypass_hooks(self): 670 def test_dcommit_bypass_hooks(self):
640 self.calls = ( 671 self.calls = (
641 self._dcommit_calls_1() + 672 self._dcommit_calls_1() +
642 self._dcommit_calls_bypassed() + 673 self._dcommit_calls_bypassed() +
643 self._dcommit_calls_3()) 674 self._dcommit_calls_3())
644 git_cl.main(['dcommit', '--bypass-hooks']) 675 git_cl.main(['dcommit', '--bypass-hooks'])
645 676
646 677
647 @classmethod 678 @classmethod
679 def _gerrit_ensure_auth_calls(cls, issue=None):
680 calls = []
681 if issue:
682 calls.extend([
683 ((['git', 'config', 'branch.master.gerritserver'],), ''),
684 ])
685 calls.extend([
686 ((['git', 'config', 'branch.master.merge'],), 'refs/heads/master'),
687 ((['git', 'config', 'branch.master.remote'],), 'origin'),
688 ((['git', 'config', 'remote.origin.url'],),
689 'https://chromium.googlesource.com/my/repo'),
690 ((['git', 'config', 'remote.origin.url'],),
691 'https://chromium.googlesource.com/my/repo'),
692 ])
693 return calls
694
695 @classmethod
648 def _gerrit_base_calls(cls, issue=None): 696 def _gerrit_base_calls(cls, issue=None):
649 return [ 697 return [
650 ((['git', 'symbolic-ref', 'HEAD'],), 'master'), 698 ((['git', 'symbolic-ref', 'HEAD'],), 'master'),
651 ((['git', 'config', '--int', '--get', 699 ((['git', 'config', '--int', '--get',
652 'branch.master.git-cl-similarity'],), ''), 700 'branch.master.git-cl-similarity'],), ''),
653 ((['git', 'symbolic-ref', 'HEAD'],), 'master'), 701 ((['git', 'symbolic-ref', 'HEAD'],), 'master'),
654 ((['git', 'config', '--int', '--get', 702 ((['git', 'config', '--int', '--get',
655 'branch.master.git-find-copies'],), ''), 703 'branch.master.git-find-copies'],), ''),
656 ] + cls._is_gerrit_calls(True) + [ 704 ] + cls._is_gerrit_calls(True) + [
657 ((['git', 'symbolic-ref', 'HEAD'],), 'master'), 705 ((['git', 'symbolic-ref', 'HEAD'],), 'master'),
658 ((['git', 'config', 'branch.master.rietveldissue'],), ''), 706 ((['git', 'config', 'branch.master.rietveldissue'],), ''),
659 ((['git', 'config', 'branch.master.gerritissue'],), 707 ((['git', 'config', 'branch.master.gerritissue'],),
660 '' if issue is None else str(issue)), 708 '' if issue is None else str(issue)),
661 ((['git', 'config', 'branch.master.merge'],), 'master'), 709 ((['git', 'config', 'branch.master.merge'],), 'refs/heads/master'),
662 ((['git', 'config', 'branch.master.remote'],), 'origin'), 710 ((['git', 'config', 'branch.master.remote'],), 'origin'),
663 ((['get_or_create_merge_base', 'master', 'master'],), 711 ((['get_or_create_merge_base', 'master',
712 'refs/remotes/origin/master'],),
664 'fake_ancestor_sha'), 713 'fake_ancestor_sha'),
665 ] + cls._git_sanity_checks('fake_ancestor_sha', 'master') + [ 714 # Calls to verify branch point is ancestor
715 ] + (cls._gerrit_ensure_auth_calls(issue=issue) +
716 cls._git_sanity_checks('fake_ancestor_sha', 'master',
717 get_remote_branch=False)) + [
666 ((['git', 'rev-parse', '--show-cdup'],), ''), 718 ((['git', 'rev-parse', '--show-cdup'],), ''),
667 ((['git', 'rev-parse', 'HEAD'],), '12345'), 719 ((['git', 'rev-parse', 'HEAD'],), '12345'),
720
668 ((['git', 721 ((['git',
669 'diff', '--name-status', '--no-renames', '-r', 722 'diff', '--name-status', '--no-renames', '-r',
670 'fake_ancestor_sha...', '.'],), 723 'fake_ancestor_sha...', '.'],),
671 'M\t.gitignore\n'), 724 'M\t.gitignore\n'),
672 ((['git', 'config', 'branch.master.gerritpatchset'],), ''), 725 ((['git', 'config', 'branch.master.gerritpatchset'],), ''),
673 ] + ([] if issue else [ 726 ] + ([] if issue else [
674 ((['git', 727 ((['git',
675 'log', '--pretty=format:%s%n%n%b', 'fake_ancestor_sha...'],), 728 'log', '--pretty=format:%s%n%n%b', 'fake_ancestor_sha...'],),
676 'foo'), 729 'foo'),
677 ]) + [ 730 ]) + [
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
723 calls += [ 776 calls += [
724 ((['git', 'config', 'core.editor'],), ''), 777 ((['git', 'config', 'core.editor'],), ''),
725 ((['RunEditor'],), description), 778 ((['RunEditor'],), description),
726 ] 779 ]
727 ref_to_push = 'abcdef0123456789' 780 ref_to_push = 'abcdef0123456789'
728 calls += [ 781 calls += [
729 ((['git', 'config', 'branch.master.merge'],), 782 ((['git', 'config', 'branch.master.merge'],),
730 'refs/heads/master'), 783 'refs/heads/master'),
731 ((['git', 'config', 'branch.master.remote'],), 784 ((['git', 'config', 'branch.master.remote'],),
732 'origin'), 785 'origin'),
733 ((['get_or_create_merge_base', 'master', 'master'],), 786 ((['get_or_create_merge_base', 'master',
787 'refs/remotes/origin/master'],),
734 'origin/master'), 788 'origin/master'),
735 ((['git', 'rev-parse', 'HEAD:'],), 789 ((['git', 'rev-parse', 'HEAD:'],),
736 '0123456789abcdef'), 790 '0123456789abcdef'),
737 ((['git', 'commit-tree', '0123456789abcdef', '-p', 791 ((['git', 'commit-tree', '0123456789abcdef', '-p',
738 'origin/master', '-m', description],), 792 'origin/master', '-m', description],),
739 ref_to_push), 793 ref_to_push),
740 ] 794 ]
741 else: 795 else:
742 ref_to_push = 'HEAD' 796 ref_to_push = 'HEAD'
743 797
(...skipping 23 matching lines...) Expand all
767 'remote:\n' 821 'remote:\n'
768 'remote: New Changes:\n' 822 'remote: New Changes:\n'
769 'remote: https://chromium-review.googlesource.com/123456 XXX.\n' 823 'remote: https://chromium-review.googlesource.com/123456 XXX.\n'
770 'remote:\n' 824 'remote:\n'
771 'To https://chromium.googlesource.com/yyy/zzz\n' 825 'To https://chromium.googlesource.com/yyy/zzz\n'
772 ' * [new branch] hhhh -> refs/for/refs/heads/master\n')), 826 ' * [new branch] hhhh -> refs/for/refs/heads/master\n')),
773 ] 827 ]
774 if squash: 828 if squash:
775 calls += [ 829 calls += [
776 ((['git', 'config', 'branch.master.gerritissue', '123456'],), ''), 830 ((['git', 'config', 'branch.master.gerritissue', '123456'],), ''),
777 ((['git', 'config', 'branch.master.gerritserver'],), ''),
778 ((['git', 'config', 'remote.origin.url'],),
779 'https://chromium.googlesource.com/my/repo.git'),
780 ((['git', 'config', 'branch.master.gerritserver', 831 ((['git', 'config', 'branch.master.gerritserver',
781 'https://chromium-review.googlesource.com'],), ''), 832 'https://chromium-review.googlesource.com'],), ''),
782 ((['git', 'config', 'branch.master.gerritsquashhash', 833 ((['git', 'config', 'branch.master.gerritsquashhash',
783 'abcdef0123456789'],), ''), 834 'abcdef0123456789'],), ''),
784 ] 835 ]
785 calls += cls._git_post_upload_calls() 836 calls += cls._git_post_upload_calls()
786 return calls 837 return calls
787 838
788 def _run_gerrit_upload_test( 839 def _run_gerrit_upload_test(
789 self, 840 self,
790 upload_args, 841 upload_args,
791 description, 842 description,
792 reviewers, 843 reviewers,
793 squash=False, 844 squash=False,
794 expected_upstream_ref='origin/refs/heads/master', 845 expected_upstream_ref='origin/refs/heads/master',
795 post_amend_description=None, 846 post_amend_description=None,
796 issue=None): 847 issue=None):
797 """Generic gerrit upload test framework.""" 848 """Generic gerrit upload test framework."""
849 self.mock(git_cl.gerrit_util, "CookiesAuthenticator",
850 CookiesAuthenticatorMockFactory(same_cookie='same_cred'))
798 self.calls = self._gerrit_base_calls(issue=issue) 851 self.calls = self._gerrit_base_calls(issue=issue)
799 self.calls += self._gerrit_upload_calls( 852 self.calls += self._gerrit_upload_calls(
800 description, reviewers, squash, 853 description, reviewers, squash,
801 expected_upstream_ref=expected_upstream_ref, 854 expected_upstream_ref=expected_upstream_ref,
802 post_amend_description=post_amend_description, 855 post_amend_description=post_amend_description,
803 issue=issue) 856 issue=issue)
804 # Uncomment when debugging. 857 # Uncomment when debugging.
805 # print '\n'.join(map(lambda x: '%2i: %s' % x, enumerate(self.calls))) 858 # print '\n'.join(map(lambda x: '%2i: %s' % x, enumerate(self.calls)))
806 git_cl.main(['upload'] + upload_args) 859 git_cl.main(['upload'] + upload_args)
807 860
(...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after
1186 ((['git', 'config', '--local', '--get-regexp', 1239 ((['git', 'config', '--local', '--get-regexp',
1187 'branch\\..*\\.rietveldissue'], ), '', 1240 'branch\\..*\\.rietveldissue'], ), '',
1188 subprocess2.CalledProcessError(1, '', '', '', '')), 1241 subprocess2.CalledProcessError(1, '', '', '', '')),
1189 ((['git', 'config', '--local', '--get-regexp', 1242 ((['git', 'config', '--local', '--get-regexp',
1190 'branch\\..*\\.gerritissue'], ), '', 1243 'branch\\..*\\.gerritissue'], ), '',
1191 subprocess2.CalledProcessError(1, '', '', '', '')), 1244 subprocess2.CalledProcessError(1, '', '', '', '')),
1192 1245
1193 ] 1246 ]
1194 self.assertEqual(1, git_cl.main(['checkout', '99999'])) 1247 self.assertEqual(1, git_cl.main(['checkout', '99999']))
1195 1248
1249 def _test_gerrit_ensure_authenticated_common(self, auth):
1250 self.mock(git_cl.gerrit_util, 'CookiesAuthenticator',
1251 CookiesAuthenticatorMockFactory(hosts_with_creds=auth))
1252 self.mock(git_cl, 'DieWithError',
1253 lambda msg: self._mocked_call(['DieWithError', msg]))
1254 self.mock(git_cl, 'ask_for_data',
1255 lambda msg: self._mocked_call(['ask_for_data', msg]))
1256 self.calls = [
1257 ((['git', 'symbolic-ref', 'HEAD'],), 'master')
1258 ] + self._gerrit_ensure_auth_calls()
1259 cl = git_cl.Changelist(codereview='gerrit')
1260 cl.lookedup_issue = True
1261 return cl
1262
1263 def test_gerrit_ensure_authenticated_missing(self):
1264 cl = self._test_gerrit_ensure_authenticated_common(auth={
1265 'chromium.googlesource.com': 'git is ok, but gerrit one is missing',
1266 })
1267 self.calls.append(
1268 ((['DieWithError',
1269 'Credentials for the following hosts are required:\n'
1270 ' chromium-review.googlesource.com\n'
1271 'These are read from ~/.gitcookies (or legacy ~/.netrc)\n'
1272 'You can (re)generate your credentails by visiting '
1273 'https://chromium-review.googlesource.com/new-password'],), ''),)
1274 self.assertIsNone(cl.EnsureAuthenticated(force=False))
1275
1276 def test_gerrit_ensure_authenticated_conflict(self):
1277 cl = self._test_gerrit_ensure_authenticated_common(auth={
1278 'chromium.googlesource.com': 'one',
1279 'chromium-review.googlesource.com': 'other',
1280 })
1281 self.calls.append(
1282 ((['ask_for_data', 'If you know what you are doing, '
1283 'press Enter to continue, Ctrl+C to abort.'],), ''))
1284 self.assertIsNone(cl.EnsureAuthenticated(force=False))
1285
1286 def test_gerrit_ensure_authenticated_ok(self):
1287 cl = self._test_gerrit_ensure_authenticated_common(auth={
1288 'chromium.googlesource.com': 'same',
1289 'chromium-review.googlesource.com': 'same',
1290 })
1291 self.assertIsNone(cl.EnsureAuthenticated(force=False))
1292
1196 1293
1197 if __name__ == '__main__': 1294 if __name__ == '__main__':
1198 git_cl.logging.basicConfig( 1295 git_cl.logging.basicConfig(
1199 level=git_cl.logging.DEBUG if '-v' in sys.argv else git_cl.logging.ERROR) 1296 level=git_cl.logging.DEBUG if '-v' in sys.argv else git_cl.logging.ERROR)
1200 unittest.main() 1297 unittest.main()
OLDNEW
« no previous file with comments | « git_cl.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698