split_cl_test.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #!/usr/bin/env vpython3
  2. """Tests for split_cl."""
  3. import os
  4. import sys
  5. import unittest
  6. from unittest import mock
  7. sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  8. import split_cl
  9. class SplitClTest(unittest.TestCase):
  10. def testAddUploadedByGitClSplitToDescription(self):
  11. description = """Convert use of X to Y in $directory
  12. <add some background about this conversion for the reviewers>
  13. """
  14. footers = 'Bug: 12345'
  15. added_line = 'This CL was uploaded by git cl split.'
  16. # Description without footers
  17. self.assertEqual(
  18. split_cl.AddUploadedByGitClSplitToDescription(description),
  19. description + added_line)
  20. # Description with footers
  21. self.assertEqual(
  22. split_cl.AddUploadedByGitClSplitToDescription(description +
  23. footers),
  24. description + added_line + '\n\n' + footers)
  25. def testFormatDescriptionOrComment(self):
  26. description = "Converted use of X to Y in $directory."
  27. # One directory
  28. self.assertEqual(
  29. split_cl.FormatDescriptionOrComment(description, ["foo"]),
  30. "Converted use of X to Y in foo.",
  31. )
  32. # Many directories
  33. self.assertEqual(
  34. split_cl.FormatDescriptionOrComment(description, ["foo", "bar"]),
  35. "Converted use of X to Y in ['foo', 'bar'].",
  36. )
  37. def GetDirectoryBaseName(self, file_path):
  38. return os.path.basename(os.path.dirname(file_path))
  39. def MockSuggestOwners(self, paths, exclude=None):
  40. if not paths:
  41. return ["superowner"]
  42. return self.GetDirectoryBaseName(paths[0]).split(",")
  43. def MockIsFile(self, file_path):
  44. if os.path.basename(file_path) == "OWNERS":
  45. return "owner" in self.GetDirectoryBaseName(file_path)
  46. return True
  47. @mock.patch("os.path.isfile")
  48. def testSelectReviewersForFiles(self, mock_is_file):
  49. mock_is_file.side_effect = self.MockIsFile
  50. owners_client = mock.Mock(SuggestOwners=self.MockSuggestOwners,
  51. EVERYONE="*")
  52. cl = mock.Mock(owners_client=owners_client)
  53. files = [("M", os.path.join("foo", "owner1,owner2", "a.txt")),
  54. ("M", os.path.join("foo", "owner1,owner2", "b.txt")),
  55. ("M", os.path.join("bar", "owner1,owner2", "c.txt")),
  56. ("M", os.path.join("bax", "owner2", "d.txt")),
  57. ("M", os.path.join("baz", "owner3", "e.txt"))]
  58. files_split_by_reviewers = split_cl.SelectReviewersForFiles(
  59. cl, "author", files, 0)
  60. self.assertEqual(3, len(files_split_by_reviewers.keys()))
  61. info1 = files_split_by_reviewers[tuple(["owner1", "owner2"])]
  62. self.assertEqual(info1.files,
  63. [("M", os.path.join("foo", "owner1,owner2", "a.txt")),
  64. ("M", os.path.join("foo", "owner1,owner2", "b.txt")),
  65. ("M", os.path.join("bar", "owner1,owner2", "c.txt"))])
  66. self.assertEqual(info1.owners_directories,
  67. ["foo/owner1,owner2", "bar/owner1,owner2"])
  68. info2 = files_split_by_reviewers[tuple(["owner2"])]
  69. self.assertEqual(info2.files,
  70. [("M", os.path.join("bax", "owner2", "d.txt"))])
  71. self.assertEqual(info2.owners_directories, ["bax/owner2"])
  72. info3 = files_split_by_reviewers[tuple(["owner3"])]
  73. self.assertEqual(info3.files,
  74. [("M", os.path.join("baz", "owner3", "e.txt"))])
  75. self.assertEqual(info3.owners_directories, ["baz/owner3"])
  76. class UploadClTester:
  77. """Sets up test environment for testing split_cl.UploadCl()"""
  78. def __init__(self, test):
  79. self.mock_git_branches = self.StartPatcher("git_common.branches",
  80. test)
  81. self.mock_git_branches.return_value = []
  82. self.mock_git_current_branch = self.StartPatcher(
  83. "git_common.current_branch", test)
  84. self.mock_git_current_branch.return_value = "branch_to_upload"
  85. self.mock_git_run = self.StartPatcher("git_common.run", test)
  86. self.mock_temporary_file = self.StartPatcher(
  87. "gclient_utils.temporary_file", test)
  88. self.mock_temporary_file(
  89. ).__enter__.return_value = "temporary_file0"
  90. self.mock_file_writer = self.StartPatcher("gclient_utils.FileWrite",
  91. test)
  92. def StartPatcher(self, target, test):
  93. patcher = mock.patch(target)
  94. test.addCleanup(patcher.stop)
  95. return patcher.start()
  96. def DoUploadCl(self, directories, files, reviewers, cmd_upload):
  97. split_cl.UploadCl("branch_to_upload", "upstream_branch",
  98. directories, files, "description", None,
  99. reviewers, mock.Mock(), cmd_upload, True, True,
  100. "topic", os.path.sep)
  101. def testUploadCl(self):
  102. """Tests commands run by UploadCl."""
  103. upload_cl_tester = self.UploadClTester(self)
  104. directories = ["dir0"]
  105. files = [("M", os.path.join("bar", "a.cc")),
  106. ("D", os.path.join("foo", "b.cc"))]
  107. reviewers = {"reviewer1@gmail.com", "reviewer2@gmail.com"}
  108. mock_cmd_upload = mock.Mock()
  109. upload_cl_tester.DoUploadCl(directories, files, reviewers,
  110. mock_cmd_upload)
  111. abs_repository_path = os.path.abspath(os.path.sep)
  112. mock_git_run = upload_cl_tester.mock_git_run
  113. self.assertEqual(mock_git_run.call_count, 4)
  114. mock_git_run.assert_has_calls([
  115. mock.call("checkout", "-t", "upstream_branch", "-b",
  116. "branch_to_upload_dir0_split"),
  117. mock.call("rm", os.path.join(abs_repository_path, "foo", "b.cc")),
  118. mock.call("checkout", "branch_to_upload", "--",
  119. os.path.join(abs_repository_path, "bar", "a.cc")),
  120. mock.call("commit", "-F", "temporary_file0")
  121. ])
  122. expected_upload_args = [
  123. "-f", "-r", "reviewer1@gmail.com,reviewer2@gmail.com",
  124. "--cq-dry-run", "--send-mail", "--enable-auto-submit",
  125. "--topic=topic"
  126. ]
  127. mock_cmd_upload.assert_called_once_with(expected_upload_args)
  128. def testDontUploadClIfBranchAlreadyExists(self):
  129. """Tests that a CL is not uploaded if split branch already exists"""
  130. upload_cl_tester = self.UploadClTester(self)
  131. upload_cl_tester.mock_git_branches.return_value = [
  132. "branch0", "branch_to_upload_dir0_split"
  133. ]
  134. directories = ["dir0"]
  135. files = [("M", os.path.join("bar", "a.cc")),
  136. ("D", os.path.join("foo", "b.cc"))]
  137. reviewers = {"reviewer1@gmail.com"}
  138. mock_cmd_upload = mock.Mock()
  139. upload_cl_tester.DoUploadCl(directories, files, reviewers,
  140. mock_cmd_upload)
  141. upload_cl_tester.mock_git_run.assert_not_called()
  142. mock_cmd_upload.assert_not_called()
  143. @mock.patch("gclient_utils.AskForData")
  144. def testCheckDescriptionBugLink(self, mock_ask_for_data):
  145. # Description contains bug link.
  146. self.assertTrue(split_cl.CheckDescriptionBugLink("Bug:1234"))
  147. self.assertEqual(mock_ask_for_data.call_count, 0)
  148. # Description does not contain bug link. User does not enter 'y' when
  149. # prompted.
  150. mock_ask_for_data.reset_mock()
  151. mock_ask_for_data.return_value = "m"
  152. self.assertFalse(split_cl.CheckDescriptionBugLink("Description"))
  153. self.assertEqual(mock_ask_for_data.call_count, 1)
  154. # Description does not contain bug link. User enters 'y' when prompted.
  155. mock_ask_for_data.reset_mock()
  156. mock_ask_for_data.return_value = "y"
  157. self.assertTrue(split_cl.CheckDescriptionBugLink("Description"))
  158. self.assertEqual(mock_ask_for_data.call_count, 1)
  159. if __name__ == '__main__':
  160. unittest.main()