func_test.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. # -*- coding: utf-8 -*-
  2. # SPDX-License-Identifier: GPL-2.0+
  3. #
  4. # Copyright 2017 Google, Inc
  5. #
  6. import contextlib
  7. import os
  8. import re
  9. import shutil
  10. import sys
  11. import tempfile
  12. import unittest
  13. import gitutil
  14. import patchstream
  15. import settings
  16. @contextlib.contextmanager
  17. def capture():
  18. import sys
  19. from cStringIO import StringIO
  20. oldout,olderr = sys.stdout, sys.stderr
  21. try:
  22. out=[StringIO(), StringIO()]
  23. sys.stdout,sys.stderr = out
  24. yield out
  25. finally:
  26. sys.stdout,sys.stderr = oldout, olderr
  27. out[0] = out[0].getvalue()
  28. out[1] = out[1].getvalue()
  29. class TestFunctional(unittest.TestCase):
  30. def setUp(self):
  31. self.tmpdir = tempfile.mkdtemp(prefix='patman.')
  32. def tearDown(self):
  33. shutil.rmtree(self.tmpdir)
  34. @staticmethod
  35. def GetPath(fname):
  36. return os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
  37. 'test', fname)
  38. @classmethod
  39. def GetText(self, fname):
  40. return open(self.GetPath(fname)).read()
  41. @classmethod
  42. def GetPatchName(self, subject):
  43. fname = re.sub('[ :]', '-', subject)
  44. return fname.replace('--', '-')
  45. def CreatePatchesForTest(self, series):
  46. cover_fname = None
  47. fname_list = []
  48. for i, commit in enumerate(series.commits):
  49. clean_subject = self.GetPatchName(commit.subject)
  50. src_fname = '%04d-%s.patch' % (i + 1, clean_subject[:52])
  51. fname = os.path.join(self.tmpdir, src_fname)
  52. shutil.copy(self.GetPath(src_fname), fname)
  53. fname_list.append(fname)
  54. if series.get('cover'):
  55. src_fname = '0000-cover-letter.patch'
  56. cover_fname = os.path.join(self.tmpdir, src_fname)
  57. fname = os.path.join(self.tmpdir, src_fname)
  58. shutil.copy(self.GetPath(src_fname), fname)
  59. return cover_fname, fname_list
  60. def testBasic(self):
  61. """Tests the basic flow of patman
  62. This creates a series from some hard-coded patches build from a simple
  63. tree with the following metadata in the top commit:
  64. Series-to: u-boot
  65. Series-prefix: RFC
  66. Series-cc: Stefan Brüns <stefan.bruens@rwth-aachen.de>
  67. Cover-letter-cc: Lord Mëlchett <clergy@palace.gov>
  68. Series-version: 2
  69. Series-changes: 4
  70. - Some changes
  71. Cover-letter:
  72. test: A test patch series
  73. This is a test of how the cover
  74. leter
  75. works
  76. END
  77. and this in the first commit:
  78. Series-notes:
  79. some notes
  80. about some things
  81. from the first commit
  82. END
  83. Commit-notes:
  84. Some notes about
  85. the first commit
  86. END
  87. with the following commands:
  88. git log -n2 --reverse >/path/to/tools/patman/test/test01.txt
  89. git format-patch --subject-prefix RFC --cover-letter HEAD~2
  90. mv 00* /path/to/tools/patman/test
  91. It checks these aspects:
  92. - git log can be processed by patchstream
  93. - emailing patches uses the correct command
  94. - CC file has information on each commit
  95. - cover letter has the expected text and subject
  96. - each patch has the correct subject
  97. - dry-run information prints out correctly
  98. - unicode is handled correctly
  99. - Series-to, Series-cc, Series-prefix, Cover-letter
  100. - Cover-letter-cc, Series-version, Series-changes, Series-notes
  101. - Commit-notes
  102. """
  103. process_tags = True
  104. ignore_bad_tags = True
  105. stefan = u'Stefan Brüns <stefan.bruens@rwth-aachen.de>'
  106. rick = 'Richard III <richard@palace.gov>'
  107. mel = u'Lord Mëlchett <clergy@palace.gov>'
  108. ed = u'Lond Edmund Blackaddër <weasel@blackadder.org'
  109. fred = 'Fred Bloggs <f.bloggs@napier.net>'
  110. add_maintainers = [stefan, rick]
  111. dry_run = True
  112. in_reply_to = mel
  113. count = 2
  114. settings.alias = {
  115. 'fdt': ['simon'],
  116. 'u-boot': ['u-boot@lists.denx.de'],
  117. 'simon': [ed],
  118. 'fred': [fred],
  119. }
  120. text = self.GetText('test01.txt')
  121. series = patchstream.GetMetaDataForTest(text)
  122. cover_fname, args = self.CreatePatchesForTest(series)
  123. with capture() as out:
  124. patchstream.FixPatches(series, args)
  125. if cover_fname and series.get('cover'):
  126. patchstream.InsertCoverLetter(cover_fname, series, count)
  127. series.DoChecks()
  128. cc_file = series.MakeCcFile(process_tags, cover_fname,
  129. not ignore_bad_tags, add_maintainers,
  130. None)
  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])