git_rebase_update_test.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. #!/usr/bin/env python
  2. # Copyright 2014 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """Unit tests for git_rebase_update.py"""
  6. import os
  7. import sys
  8. DEPOT_TOOLS_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  9. sys.path.insert(0, DEPOT_TOOLS_ROOT)
  10. from testing_support import coverage_utils
  11. from testing_support import git_test_utils
  12. class GitRebaseUpdateTest(git_test_utils.GitRepoReadWriteTestBase):
  13. REPO_SCHEMA = """
  14. A B C D E F G
  15. B H I J K
  16. J L
  17. """
  18. @classmethod
  19. def getRepoContent(cls, commit):
  20. # Every commit X gets a file X with the content X
  21. return {commit: {'data': commit}}
  22. @classmethod
  23. def setUpClass(cls):
  24. super(GitRebaseUpdateTest, cls).setUpClass()
  25. import git_rebase_update, git_new_branch, git_reparent_branch, git_common
  26. import git_rename_branch
  27. cls.reup = git_rebase_update
  28. cls.rp = git_reparent_branch
  29. cls.nb = git_new_branch
  30. cls.mv = git_rename_branch
  31. cls.gc = git_common
  32. cls.gc.TEST_MODE = True
  33. def setUp(self):
  34. super(GitRebaseUpdateTest, self).setUp()
  35. # Include branch_K, branch_L to make sure that ABCDEFG all get the
  36. # same commit hashes as self.repo. Otherwise they get committed with the
  37. # wrong timestamps, due to commit ordering.
  38. # TODO(iannucci): Make commit timestamps deterministic in left to right, top
  39. # to bottom order, not in lexi-topographical order.
  40. origin_schema = git_test_utils.GitRepoSchema("""
  41. A B C D E F G M N O
  42. B H I J K
  43. J L
  44. """, self.getRepoContent)
  45. self.origin = origin_schema.reify()
  46. self.origin.git('checkout', 'master')
  47. self.origin.git('branch', '-d', *['branch_'+l for l in 'KLG'])
  48. self.repo.git('remote', 'add', 'origin', self.origin.repo_path)
  49. self.repo.git('config', '--add', 'remote.origin.fetch',
  50. '+refs/tags/*:refs/tags/*')
  51. self.repo.git('update-ref', 'refs/remotes/origin/master', 'tag_E')
  52. self.repo.git('branch', '--set-upstream-to', 'branch_G', 'branch_K')
  53. self.repo.git('branch', '--set-upstream-to', 'branch_K', 'branch_L')
  54. self.repo.git('branch', '--set-upstream-to', 'origin/master', 'branch_G')
  55. self.repo.to_schema_refs += ['origin/master']
  56. def tearDown(self):
  57. self.origin.nuke()
  58. super(GitRebaseUpdateTest, self).tearDown()
  59. def testRebaseUpdate(self):
  60. self.repo.git('checkout', 'branch_K')
  61. self.repo.run(self.nb.main, ['foobar'])
  62. self.assertEqual(self.repo.git('rev-parse', 'HEAD').stdout,
  63. self.repo.git('rev-parse', 'origin/master').stdout)
  64. with self.repo.open('foobar', 'w') as f:
  65. f.write('this is the foobar file')
  66. self.repo.git('add', 'foobar')
  67. self.repo.git_commit('foobar1')
  68. with self.repo.open('foobar', 'w') as f:
  69. f.write('totes the Foobar file')
  70. self.repo.git_commit('foobar2')
  71. self.repo.git('checkout', 'branch_K')
  72. self.repo.run(self.nb.main, ['--upstream_current', 'sub_K'])
  73. with self.repo.open('K', 'w') as f:
  74. f.write('This depends on K')
  75. self.repo.git_commit('sub_K')
  76. self.repo.run(self.nb.main, ['old_branch'])
  77. self.repo.git('reset', '--hard', self.repo['A'])
  78. with self.repo.open('old_file', 'w') as f:
  79. f.write('old_files we want to keep around')
  80. self.repo.git('add', 'old_file')
  81. self.repo.git_commit('old_file')
  82. self.repo.git('config', 'branch.old_branch.dormant', 'true')
  83. self.repo.git('checkout', 'origin/master')
  84. self.assertSchema("""
  85. A B H I J K sub_K
  86. J L
  87. B C D E foobar1 foobar2
  88. E F G
  89. A old_file
  90. """)
  91. self.assertEquals(self.repo['A'], self.origin['A'])
  92. self.assertEquals(self.repo['E'], self.origin['E'])
  93. with self.repo.open('bob', 'wb') as f:
  94. f.write('testing auto-freeze/thaw')
  95. output, _ = self.repo.capture_stdio(self.reup.main)
  96. self.assertIn('Cannot rebase-update', output)
  97. self.repo.git('checkout', 'branch_K')
  98. output, _ = self.repo.capture_stdio(self.reup.main)
  99. self.assertIn('Rebasing: branch_G', output)
  100. self.assertIn('Rebasing: branch_K', output)
  101. self.assertIn('Rebasing: branch_L', output)
  102. self.assertIn('Rebasing: foobar', output)
  103. self.assertIn('Rebasing: sub_K', output)
  104. self.assertIn('Deleted branch branch_G', output)
  105. self.assertIn('Reparented branch_K to track origin/master', output)
  106. self.assertSchema("""
  107. A B C D E F G M N O H I J K sub_K
  108. K L
  109. O foobar1 foobar2
  110. A old_file
  111. """)
  112. output, _ = self.repo.capture_stdio(self.reup.main)
  113. self.assertIn('branch_K up-to-date', output)
  114. self.assertIn('branch_L up-to-date', output)
  115. self.assertIn('foobar up-to-date', output)
  116. self.assertIn('sub_K up-to-date', output)
  117. with self.repo.open('bob') as f:
  118. self.assertEquals('testing auto-freeze/thaw', f.read())
  119. self.assertEqual(self.repo.git('status', '--porcelain').stdout, '?? bob\n')
  120. self.repo.git('checkout', 'origin/master')
  121. _, err = self.repo.capture_stdio(self.rp.main, ['foobar'])
  122. self.assertIn('Must be on the branch', err)
  123. self.repo.git('checkout', 'branch_K')
  124. _, err = self.repo.capture_stdio(self.rp.main, ['origin/master'])
  125. self.assertIn('Cannot reparent a branch to its existing parent', err)
  126. output, _ = self.repo.capture_stdio(self.rp.main, ['foobar'])
  127. self.assertIn('Rebasing: branch_K', output)
  128. self.assertIn('Rebasing: sub_K', output)
  129. self.assertIn('Rebasing: branch_L', output)
  130. self.assertSchema("""
  131. A B C D E F G M N O foobar1 foobar2 H I J K L
  132. K sub_K
  133. A old_file
  134. """)
  135. self.repo.git('checkout', 'sub_K')
  136. output, _ = self.repo.capture_stdio(self.rp.main, ['foobar'])
  137. self.assertIn('Squashing failed', output)
  138. self.assertTrue(self.repo.run(self.gc.in_rebase))
  139. self.repo.git('rebase', '--abort')
  140. self.assertIsNone(self.repo.run(self.gc.thaw))
  141. self.assertSchema("""
  142. A B C D E F G M N O foobar1 foobar2 H I J K L
  143. A old_file
  144. K sub_K
  145. """)
  146. self.assertEqual(self.repo.git('status', '--porcelain').stdout, '?? bob\n')
  147. branches = self.repo.run(set, self.gc.branches())
  148. self.assertEqual(branches, {'branch_K', 'master', 'sub_K', 'root_A',
  149. 'branch_L', 'old_branch', 'foobar'})
  150. self.repo.git('checkout', 'branch_K')
  151. self.repo.run(self.mv.main, ['special_K'])
  152. branches = self.repo.run(set, self.gc.branches())
  153. self.assertEqual(branches, {'special_K', 'master', 'sub_K', 'root_A',
  154. 'branch_L', 'old_branch', 'foobar'})
  155. self.repo.git('checkout', 'origin/master')
  156. _, err = self.repo.capture_stdio(self.mv.main, ['special_K', 'cool branch'])
  157. self.assertIn('fatal: \'cool branch\' is not a valid branch name.', err)
  158. self.repo.run(self.mv.main, ['special_K', 'cool_branch'])
  159. branches = self.repo.run(set, self.gc.branches())
  160. self.assertEqual(branches, {'cool_branch', 'master', 'sub_K', 'root_A',
  161. 'branch_L', 'old_branch', 'foobar'})
  162. _, branch_tree = self.repo.run(self.gc.get_branch_tree)
  163. self.assertEqual(branch_tree['sub_K'], 'foobar')
  164. def testRebaseConflicts(self):
  165. # Pretend that branch_L landed
  166. self.origin.git('checkout', 'master')
  167. with self.origin.open('L', 'w') as f:
  168. f.write('L')
  169. self.origin.git('add', 'L')
  170. self.origin.git_commit('L')
  171. # Add a commit to branch_K so that things fail
  172. self.repo.git('checkout', 'branch_K')
  173. with self.repo.open('M', 'w') as f:
  174. f.write('NOPE')
  175. self.repo.git('add', 'M')
  176. self.repo.git_commit('K NOPE')
  177. # Add a commits to branch_L which will work when squashed
  178. self.repo.git('checkout', 'branch_L')
  179. self.repo.git('reset', 'branch_L~')
  180. with self.repo.open('L', 'w') as f:
  181. f.write('NOPE')
  182. self.repo.git('add', 'L')
  183. self.repo.git_commit('L NOPE')
  184. with self.repo.open('L', 'w') as f:
  185. f.write('L')
  186. self.repo.git('add', 'L')
  187. self.repo.git_commit('L YUP')
  188. # start on a branch which will be deleted
  189. self.repo.git('checkout', 'branch_G')
  190. output, _ = self.repo.capture_stdio(self.reup.main)
  191. self.assertIn('branch.branch_K.dormant true', output)
  192. output, _ = self.repo.capture_stdio(self.reup.main)
  193. self.assertIn('Rebase in progress', output)
  194. self.repo.git('checkout', '--theirs', 'M')
  195. self.repo.git('rebase', '--skip')
  196. output, _ = self.repo.capture_stdio(self.reup.main)
  197. self.assertIn('Failed! Attempting to squash', output)
  198. self.assertIn('Deleted branch branch_G', output)
  199. self.assertIn('Deleted branch branch_L', output)
  200. self.assertIn('\'branch_G\' was merged', output)
  201. self.assertIn('checking out \'origin/master\'', output)
  202. def testTrackTag(self):
  203. self.origin.git('tag', 'lkgr', self.origin['M'])
  204. self.repo.git('tag', 'lkgr', self.repo['D'])
  205. self.repo.git('config', 'branch.branch_G.remote', '.')
  206. self.repo.git('config', 'branch.branch_G.merge', 'refs/tags/lkgr')
  207. self.assertIn(
  208. 'fatal: \'foo bar\' is not a valid branch name',
  209. self.repo.capture_stdio(self.nb.main, ['--lkgr', 'foo bar'])[1])
  210. self.repo.run(self.nb.main, ['--lkgr', 'foobar'])
  211. with self.repo.open('foobar', 'w') as f:
  212. f.write('this is the foobar file')
  213. self.repo.git('add', 'foobar')
  214. self.repo.git_commit('foobar1')
  215. with self.repo.open('foobar', 'w') as f:
  216. f.write('totes the Foobar file')
  217. self.repo.git_commit('foobar2')
  218. self.assertSchema("""
  219. A B H I J K
  220. J L
  221. B C D E F G
  222. D foobar1 foobar2
  223. """)
  224. self.assertEquals(self.repo['A'], self.origin['A'])
  225. self.assertEquals(self.repo['G'], self.origin['G'])
  226. output, _ = self.repo.capture_stdio(self.reup.main)
  227. self.assertIn('Fetching', output)
  228. self.assertIn('Rebasing: branch_G', output)
  229. self.assertIn('Rebasing: branch_K', output)
  230. self.assertIn('Rebasing: branch_L', output)
  231. self.assertIn('Rebasing: foobar', output)
  232. self.assertEquals(self.repo.git('rev-parse', 'lkgr').stdout.strip(),
  233. self.origin['M'])
  234. self.assertSchema("""
  235. A B C D E F G M N O
  236. M H I J K L
  237. M foobar1 foobar2
  238. """)
  239. _, err = self.repo.capture_stdio(self.rp.main, ['tag F'])
  240. self.assertIn('fatal: invalid reference', err)
  241. output, _ = self.repo.capture_stdio(self.rp.main, ['tag_F'])
  242. self.assertIn('to track tag_F [tag] (was lkgr [tag])', output)
  243. self.assertSchema("""
  244. A B C D E F G M N O
  245. M H I J K L
  246. F foobar1 foobar2
  247. """)
  248. output, _ = self.repo.capture_stdio(self.rp.main, ['--lkgr'])
  249. self.assertIn('to track lkgr [tag] (was tag_F [tag])', output)
  250. self.assertSchema("""
  251. A B C D E F G M N O
  252. M H I J K L
  253. M foobar1 foobar2
  254. """)
  255. output, _ = self.repo.capture_stdio(self.rp.main, ['--root'])
  256. self.assertIn('to track origin/master (was lkgr [tag])', output)
  257. self.assertSchema("""
  258. A B C D E F G M N O foobar1 foobar2
  259. M H I J K L
  260. """)
  261. if __name__ == '__main__':
  262. sys.exit(coverage_utils.covered_main((
  263. os.path.join(DEPOT_TOOLS_ROOT, 'git_rebase_update.py'),
  264. os.path.join(DEPOT_TOOLS_ROOT, 'git_new_branch.py'),
  265. os.path.join(DEPOT_TOOLS_ROOT, 'git_reparent_branch.py'),
  266. os.path.join(DEPOT_TOOLS_ROOT, 'git_rename_branch.py')
  267. )))