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