blob: dc30078ccee65aa1d8e60c34cb72a636d2f110f8 [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
Simon Glassc3a13cc2020-04-17 18:08:55 -060015from io import StringIO
Simon Glassade1e382019-05-14 15:53:49 -060016
Simon Glassbf776672020-04-17 18:09:04 -060017from patman import gitutil
18from patman import patchstream
19from patman import settings
20from patman import tools
Simon Glass6e87ae12017-05-29 15:31:31 -060021
22
23@contextlib.contextmanager
24def capture():
25 import sys
Simon Glass6e87ae12017-05-29 15:31:31 -060026 oldout,olderr = sys.stdout, sys.stderr
27 try:
28 out=[StringIO(), StringIO()]
29 sys.stdout,sys.stderr = out
30 yield out
31 finally:
32 sys.stdout,sys.stderr = oldout, olderr
33 out[0] = out[0].getvalue()
34 out[1] = out[1].getvalue()
35
36
37class TestFunctional(unittest.TestCase):
38 def setUp(self):
39 self.tmpdir = tempfile.mkdtemp(prefix='patman.')
40
41 def tearDown(self):
42 shutil.rmtree(self.tmpdir)
43
44 @staticmethod
45 def GetPath(fname):
46 return os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
47 'test', fname)
48
49 @classmethod
50 def GetText(self, fname):
Simon Glass272cd852019-10-31 07:42:51 -060051 return open(self.GetPath(fname), encoding='utf-8').read()
Simon Glass6e87ae12017-05-29 15:31:31 -060052
53 @classmethod
54 def GetPatchName(self, subject):
55 fname = re.sub('[ :]', '-', subject)
56 return fname.replace('--', '-')
57
58 def CreatePatchesForTest(self, series):
59 cover_fname = None
60 fname_list = []
61 for i, commit in enumerate(series.commits):
62 clean_subject = self.GetPatchName(commit.subject)
63 src_fname = '%04d-%s.patch' % (i + 1, clean_subject[:52])
64 fname = os.path.join(self.tmpdir, src_fname)
65 shutil.copy(self.GetPath(src_fname), fname)
66 fname_list.append(fname)
67 if series.get('cover'):
68 src_fname = '0000-cover-letter.patch'
69 cover_fname = os.path.join(self.tmpdir, src_fname)
70 fname = os.path.join(self.tmpdir, src_fname)
71 shutil.copy(self.GetPath(src_fname), fname)
72
73 return cover_fname, fname_list
74
75 def testBasic(self):
76 """Tests the basic flow of patman
77
78 This creates a series from some hard-coded patches build from a simple
79 tree with the following metadata in the top commit:
80
81 Series-to: u-boot
82 Series-prefix: RFC
83 Series-cc: Stefan Brüns <stefan.bruens@rwth-aachen.de>
84 Cover-letter-cc: Lord Mëlchett <clergy@palace.gov>
Sean Andersondc03ba42020-05-04 16:28:36 -040085 Series-version: 3
86 Patch-cc: fred
87 Series-process-log: sort, uniq
Simon Glass6e87ae12017-05-29 15:31:31 -060088 Series-changes: 4
89 - Some changes
Sean Andersondc03ba42020-05-04 16:28:36 -040090 - Multi
91 line
92 change
93
94 Commit-changes: 2
95 - Changes only for this commit
96
97 Cover-changes: 4
98 - Some notes for the cover letter
Simon Glass6e87ae12017-05-29 15:31:31 -060099
100 Cover-letter:
101 test: A test patch series
102 This is a test of how the cover
Sean Andersondc03ba42020-05-04 16:28:36 -0400103 letter
Simon Glass6e87ae12017-05-29 15:31:31 -0600104 works
105 END
106
107 and this in the first commit:
108
Sean Andersondc03ba42020-05-04 16:28:36 -0400109 Commit-changes: 2
110 - second revision change
111
Simon Glass6e87ae12017-05-29 15:31:31 -0600112 Series-notes:
113 some notes
114 about some things
115 from the first commit
116 END
117
118 Commit-notes:
119 Some notes about
120 the first commit
121 END
122
123 with the following commands:
124
125 git log -n2 --reverse >/path/to/tools/patman/test/test01.txt
126 git format-patch --subject-prefix RFC --cover-letter HEAD~2
127 mv 00* /path/to/tools/patman/test
128
129 It checks these aspects:
130 - git log can be processed by patchstream
131 - emailing patches uses the correct command
132 - CC file has information on each commit
133 - cover letter has the expected text and subject
134 - each patch has the correct subject
135 - dry-run information prints out correctly
136 - unicode is handled correctly
137 - Series-to, Series-cc, Series-prefix, Cover-letter
138 - Cover-letter-cc, Series-version, Series-changes, Series-notes
139 - Commit-notes
140 """
141 process_tags = True
142 ignore_bad_tags = True
Simon Glasse6dca5e2019-05-14 15:53:53 -0600143 stefan = b'Stefan Br\xc3\xbcns <stefan.bruens@rwth-aachen.de>'.decode('utf-8')
Simon Glass6e87ae12017-05-29 15:31:31 -0600144 rick = 'Richard III <richard@palace.gov>'
Simon Glasse6dca5e2019-05-14 15:53:53 -0600145 mel = b'Lord M\xc3\xablchett <clergy@palace.gov>'.decode('utf-8')
146 ed = b'Lond Edmund Blackadd\xc3\xabr <weasel@blackadder.org'.decode('utf-8')
Simon Glass6e87ae12017-05-29 15:31:31 -0600147 fred = 'Fred Bloggs <f.bloggs@napier.net>'
148 add_maintainers = [stefan, rick]
149 dry_run = True
150 in_reply_to = mel
151 count = 2
152 settings.alias = {
153 'fdt': ['simon'],
154 'u-boot': ['u-boot@lists.denx.de'],
155 'simon': [ed],
156 'fred': [fred],
157 }
158
159 text = self.GetText('test01.txt')
160 series = patchstream.GetMetaDataForTest(text)
161 cover_fname, args = self.CreatePatchesForTest(series)
162 with capture() as out:
163 patchstream.FixPatches(series, args)
164 if cover_fname and series.get('cover'):
165 patchstream.InsertCoverLetter(cover_fname, series, count)
166 series.DoChecks()
167 cc_file = series.MakeCcFile(process_tags, cover_fname,
Chris Packham4fb35022018-06-07 20:45:06 +1200168 not ignore_bad_tags, add_maintainers,
169 None)
Simon Glass6e87ae12017-05-29 15:31:31 -0600170 cmd = gitutil.EmailPatches(series, cover_fname, args,
171 dry_run, not ignore_bad_tags, cc_file,
172 in_reply_to=in_reply_to, thread=None)
173 series.ShowActions(args, cmd, process_tags)
Simon Glass272cd852019-10-31 07:42:51 -0600174 cc_lines = open(cc_file, encoding='utf-8').read().splitlines()
Simon Glass6e87ae12017-05-29 15:31:31 -0600175 os.remove(cc_file)
176
177 lines = out[0].splitlines()
Simon Glass6e87ae12017-05-29 15:31:31 -0600178 self.assertEqual('Cleaned %s patches' % len(series.commits), lines[0])
179 self.assertEqual('Change log missing for v2', lines[1])
180 self.assertEqual('Change log missing for v3', lines[2])
181 self.assertEqual('Change log for unknown version v4', lines[3])
182 self.assertEqual("Alias 'pci' not found", lines[4])
183 self.assertIn('Dry run', lines[5])
184 self.assertIn('Send a total of %d patches' % count, lines[7])
185 line = 8
186 for i, commit in enumerate(series.commits):
187 self.assertEqual(' %s' % args[i], lines[line + 0])
188 line += 1
189 while 'Cc:' in lines[line]:
190 line += 1
191 self.assertEqual('To: u-boot@lists.denx.de', lines[line])
Simon Glasse6dca5e2019-05-14 15:53:53 -0600192 self.assertEqual('Cc: %s' % tools.FromUnicode(stefan),
193 lines[line + 1])
Simon Glass6e87ae12017-05-29 15:31:31 -0600194 self.assertEqual('Version: 3', lines[line + 2])
195 self.assertEqual('Prefix:\t RFC', lines[line + 3])
196 self.assertEqual('Cover: 4 lines', lines[line + 4])
197 line += 5
Simon Glassb644c662019-05-14 15:53:51 -0600198 self.assertEqual(' Cc: %s' % fred, lines[line + 0])
Simon Glasse6dca5e2019-05-14 15:53:53 -0600199 self.assertEqual(' Cc: %s' % tools.FromUnicode(ed),
200 lines[line + 1])
201 self.assertEqual(' Cc: %s' % tools.FromUnicode(mel),
202 lines[line + 2])
Simon Glassb644c662019-05-14 15:53:51 -0600203 self.assertEqual(' Cc: %s' % rick, lines[line + 3])
Simon Glass6e87ae12017-05-29 15:31:31 -0600204 expected = ('Git command: git send-email --annotate '
205 '--in-reply-to="%s" --to "u-boot@lists.denx.de" '
206 '--cc "%s" --cc-cmd "%s --cc-cmd %s" %s %s'
207 % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname,
Simon Glasse6dca5e2019-05-14 15:53:53 -0600208 ' '.join(args)))
Simon Glass6e87ae12017-05-29 15:31:31 -0600209 line += 4
Simon Glasse6dca5e2019-05-14 15:53:53 -0600210 self.assertEqual(expected, tools.ToUnicode(lines[line]))
Simon Glass6e87ae12017-05-29 15:31:31 -0600211
Dmitry Torokhov8ab452d2019-10-21 20:09:56 -0700212 self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)),
Simon Glasse6dca5e2019-05-14 15:53:53 -0600213 tools.ToUnicode(cc_lines[0]))
Dmitry Torokhov8ab452d2019-10-21 20:09:56 -0700214 self.assertEqual(('%s %s\0%s\0%s\0%s' % (args[1], fred, ed, rick,
Simon Glasse6dca5e2019-05-14 15:53:53 -0600215 stefan)), tools.ToUnicode(cc_lines[1]))
Simon Glass6e87ae12017-05-29 15:31:31 -0600216
217 expected = '''
218This is a test of how the cover
Sean Andersondc03ba42020-05-04 16:28:36 -0400219letter
Simon Glass6e87ae12017-05-29 15:31:31 -0600220works
221
222some notes
223about some things
224from the first commit
225
226Changes in v4:
Sean Andersondc03ba42020-05-04 16:28:36 -0400227- Multi
228 line
229 change
Simon Glass6e87ae12017-05-29 15:31:31 -0600230- Some changes
Sean Andersondc03ba42020-05-04 16:28:36 -0400231- Some notes for the cover letter
Simon Glass6e87ae12017-05-29 15:31:31 -0600232
233Simon Glass (2):
234 pci: Correct cast for sandbox
Siva Durga Prasad Paladugu12308b12018-07-16 15:56:11 +0530235 fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base()
Simon Glass6e87ae12017-05-29 15:31:31 -0600236
237 cmd/pci.c | 3 ++-
238 fs/fat/fat.c | 1 +
239 lib/efi_loader/efi_memory.c | 1 +
240 lib/fdtdec.c | 3 ++-
241 4 files changed, 6 insertions(+), 2 deletions(-)
242
243--\x20
2442.7.4
245
246'''
Simon Glass272cd852019-10-31 07:42:51 -0600247 lines = open(cover_fname, encoding='utf-8').read().splitlines()
Simon Glass6e87ae12017-05-29 15:31:31 -0600248 self.assertEqual(
249 'Subject: [RFC PATCH v3 0/2] test: A test patch series',
250 lines[3])
251 self.assertEqual(expected.splitlines(), lines[7:])
252
253 for i, fname in enumerate(args):
Simon Glass272cd852019-10-31 07:42:51 -0600254 lines = open(fname, encoding='utf-8').read().splitlines()
Simon Glass6e87ae12017-05-29 15:31:31 -0600255 subject = [line for line in lines if line.startswith('Subject')]
256 self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count),
257 subject[0][:18])
Sean Andersondc03ba42020-05-04 16:28:36 -0400258
259 # Check that we got our commit notes
260 start = 0
261 expected = ''
262
Simon Glass6e87ae12017-05-29 15:31:31 -0600263 if i == 0:
Sean Andersondc03ba42020-05-04 16:28:36 -0400264 start = 17
265 expected = '''---
266Some notes about
267the first commit
268
269(no changes since v2)
270
271Changes in v2:
272- second revision change'''
273 elif i == 1:
274 start = 17
275 expected = '''---
276
277Changes in v4:
278- Multi
279 line
280 change
281- Some changes
282
283Changes in v2:
284- Changes only for this commit'''
285
286 if expected:
287 expected = expected.splitlines()
288 self.assertEqual(expected, lines[start:(start+len(expected))])