func_test.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright 2017 Google, Inc
  4. #
  5. # SPDX-License-Identifier: GPL-2.0+
  6. #
  7. import contextlib
  8. import os
  9. import re
  10. import shutil
  11. import sys
  12. import tempfile
  13. import unittest
  14. import gitutil
  15. import patchstream
  16. import settings
  17. @contextlib.contextmanager
  18. def capture():
  19. import sys
  20. from cStringIO import StringIO
  21. oldout,olderr = sys.stdout, sys.stderr
  22. try:
  23. out=[StringIO(), StringIO()]
  24. sys.stdout,sys.stderr = out
  25. yield out
  26. finally:
  27. sys.stdout,sys.stderr = oldout, olderr
  28. out[0] = out[0].getvalue()
  29. out[1] = out[1].getvalue()
  30. class TestFunctional(unittest.TestCase):
  31. def setUp(self):
  32. self.tmpdir = tempfile.mkdtemp(prefix='patman.')
  33. def tearDown(self):
  34. shutil.rmtree(self.tmpdir)
  35. @staticmethod
  36. def GetPath(fname):
  37. return os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
  38. 'test', fname)
  39. @classmethod
  40. def GetText(self, fname):
  41. return open(self.GetPath(fname)).read()
  42. @classmethod
  43. def GetPatchName(self, subject):
  44. fname = re.sub('[ :]', '-', subject)
  45. return fname.replace('--', '-')
  46. def CreatePatchesForTest(self, series):
  47. cover_fname = None
  48. fname_list = []
  49. for i, commit in enumerate(series.commits):
  50. clean_subject = self.GetPatchName(commit.subject)
  51. src_fname = '%04d-%s.patch' % (i + 1, clean_subject[:52])
  52. fname = os.path.join(self.tmpdir, src_fname)
  53. shutil.copy(self.GetPath(src_fname), fname)
  54. fname_list.append(fname)
  55. if series.get('cover'):
  56. src_fname = '0000-cover-letter.patch'
  57. cover_fname = os.path.join(self.tmpdir, src_fname)
  58. fname = os.path.join(self.tmpdir, src_fname)
  59. shutil.copy(self.GetPath(src_fname), fname)
  60. return cover_fname, fname_list
  61. def testBasic(self):
  62. """Tests the basic flow of patman
  63. This creates a series from some hard-coded patches build from a simple
  64. tree with the following metadata in the top commit:
  65. Series-to: u-boot
  66. Series-prefix: RFC
  67. Series-cc: Stefan Brüns <stefan.bruens@rwth-aachen.de>
  68. Cover-letter-cc: Lord Mëlchett <clergy@palace.gov>
  69. Series-version: 2
  70. Series-changes: 4
  71. - Some changes
  72. Cover-letter:
  73. test: A test patch series
  74. This is a test of how the cover
  75. leter
  76. works
  77. END
  78. and this in the first commit:
  79. Series-notes:
  80. some notes
  81. about some things
  82. from the first commit
  83. END
  84. Commit-notes:
  85. Some notes about
  86. the first commit
  87. END
  88. with the following commands:
  89. git log -n2 --reverse >/path/to/tools/patman/test/test01.txt
  90. git format-patch --subject-prefix RFC --cover-letter HEAD~2
  91. mv 00* /path/to/tools/patman/test
  92. It checks these aspects:
  93. - git log can be processed by patchstream
  94. - emailing patches uses the correct command
  95. - CC file has information on each commit
  96. - cover letter has the expected text and subject
  97. - each patch has the correct subject
  98. - dry-run information prints out correctly
  99. - unicode is handled correctly
  100. - Series-to, Series-cc, Series-prefix, Cover-letter
  101. - Cover-letter-cc, Series-version, Series-changes, Series-notes
  102. - Commit-notes
  103. """
  104. process_tags = True
  105. ignore_bad_tags = True
  106. stefan = u'Stefan Brüns <stefan.bruens@rwth-aachen.de>'
  107. rick = 'Richard III <richard@palace.gov>'
  108. mel = u'Lord Mëlchett <clergy@palace.gov>'
  109. ed = u'Lond Edmund Blackaddër <weasel@blackadder.org'
  110. fred = 'Fred Bloggs <f.bloggs@napier.net>'
  111. add_maintainers = [stefan, rick]
  112. dry_run = True
  113. in_reply_to = mel
  114. count = 2
  115. settings.alias = {
  116. 'fdt': ['simon'],
  117. 'u-boot': ['u-boot@lists.denx.de'],
  118. 'simon': [ed],
  119. 'fred': [fred],
  120. }
  121. text = self.GetText('test01.txt')
  122. series = patchstream.GetMetaDataForTest(text)
  123. cover_fname, args = self.CreatePatchesForTest(series)
  124. with capture() as out:
  125. patchstream.FixPatches(series, args)
  126. if cover_fname and series.get('cover'):
  127. patchstream.InsertCoverLetter(cover_fname, series, count)
  128. series.DoChecks()
  129. cc_file = series.MakeCcFile(process_tags, cover_fname,
  130. not ignore_bad_tags, add_maintainers)
  131. cmd = gitutil.EmailPatches(series, cover_fname, args,
  132. dry_run, not ignore_bad_tags, cc_file,
  133. in_reply_to=in_reply_to, thread=None)
  134. series.ShowActions(args, cmd, process_tags)
  135. cc_lines = open(cc_file).read().splitlines()
  136. os.remove(cc_file)
  137. lines = out[0].splitlines()
  138. #print '\n'.join(lines)
  139. self.assertEqual('Cleaned %s patches' % len(series.commits), lines[0])
  140. self.assertEqual('Change log missing for v2', lines[1])
  141. self.assertEqual('Change log missing for v3', lines[2])
  142. self.assertEqual('Change log for unknown version v4', lines[3])
  143. self.assertEqual("Alias 'pci' not found", lines[4])
  144. self.assertIn('Dry run', lines[5])
  145. self.assertIn('Send a total of %d patches' % count, lines[7])
  146. line = 8
  147. for i, commit in enumerate(series.commits):
  148. self.assertEqual(' %s' % args[i], lines[line + 0])
  149. line += 1
  150. while 'Cc:' in lines[line]:
  151. line += 1
  152. self.assertEqual('To: u-boot@lists.denx.de', lines[line])
  153. self.assertEqual('Cc: %s' % stefan.encode('utf-8'), lines[line + 1])
  154. self.assertEqual('Version: 3', lines[line + 2])
  155. self.assertEqual('Prefix:\t RFC', lines[line + 3])
  156. self.assertEqual('Cover: 4 lines', lines[line + 4])
  157. line += 5
  158. self.assertEqual(' Cc: %s' % mel.encode('utf-8'), lines[line + 0])
  159. self.assertEqual(' Cc: %s' % rick, lines[line + 1])
  160. self.assertEqual(' Cc: %s' % fred, lines[line + 2])
  161. self.assertEqual(' Cc: %s' % ed.encode('utf-8'), lines[line + 3])
  162. expected = ('Git command: git send-email --annotate '
  163. '--in-reply-to="%s" --to "u-boot@lists.denx.de" '
  164. '--cc "%s" --cc-cmd "%s --cc-cmd %s" %s %s'
  165. % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname,
  166. ' '.join(args))).encode('utf-8')
  167. line += 4
  168. self.assertEqual(expected, lines[line])
  169. self.assertEqual(('%s %s, %s' % (args[0], rick, stefan))
  170. .encode('utf-8'), cc_lines[0])
  171. self.assertEqual(('%s %s, %s, %s, %s' % (args[1], fred, rick, stefan,
  172. ed)).encode('utf-8'), cc_lines[1])
  173. expected = '''
  174. This is a test of how the cover
  175. leter
  176. works
  177. some notes
  178. about some things
  179. from the first commit
  180. Changes in v4:
  181. - Some changes
  182. Simon Glass (2):
  183. pci: Correct cast for sandbox
  184. fdt: Correct cast for sandbox in fdtdec_setup_memory_size()
  185. cmd/pci.c | 3 ++-
  186. fs/fat/fat.c | 1 +
  187. lib/efi_loader/efi_memory.c | 1 +
  188. lib/fdtdec.c | 3 ++-
  189. 4 files changed, 6 insertions(+), 2 deletions(-)
  190. --\x20
  191. 2.7.4
  192. '''
  193. lines = open(cover_fname).read().splitlines()
  194. #print '\n'.join(lines)
  195. self.assertEqual(
  196. 'Subject: [RFC PATCH v3 0/2] test: A test patch series',
  197. lines[3])
  198. self.assertEqual(expected.splitlines(), lines[7:])
  199. for i, fname in enumerate(args):
  200. lines = open(fname).read().splitlines()
  201. #print '\n'.join(lines)
  202. subject = [line for line in lines if line.startswith('Subject')]
  203. self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count),
  204. subject[0][:18])
  205. if i == 0:
  206. # Check that we got our commit notes
  207. self.assertEqual('---', lines[17])
  208. self.assertEqual('Some notes about', lines[18])
  209. self.assertEqual('the first commit', lines[19])