blob: 76319fff37e3df6f0fc3bd515c92209470658ce1 [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 Glassade1e382019-05-14 15:53:49 -060015try:
16 from StringIO import StringIO
17except ImportError:
18 from io import StringIO
19
Simon Glass6e87ae12017-05-29 15:31:31 -060020import gitutil
21import patchstream
22import settings
Simon Glassade1e382019-05-14 15:53:49 -060023import tools
Simon Glass6e87ae12017-05-29 15:31:31 -060024
25
26@contextlib.contextmanager
27def capture():
28 import sys
Simon Glass6e87ae12017-05-29 15:31:31 -060029 oldout,olderr = sys.stdout, sys.stderr
30 try:
31 out=[StringIO(), StringIO()]
32 sys.stdout,sys.stderr = out
33 yield out
34 finally:
35 sys.stdout,sys.stderr = oldout, olderr
36 out[0] = out[0].getvalue()
37 out[1] = out[1].getvalue()
38
39
40class TestFunctional(unittest.TestCase):
41 def setUp(self):
42 self.tmpdir = tempfile.mkdtemp(prefix='patman.')
43
44 def tearDown(self):
45 shutil.rmtree(self.tmpdir)
46
47 @staticmethod
48 def GetPath(fname):
49 return os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
50 'test', fname)
51
52 @classmethod
53 def GetText(self, fname):
Simon Glass272cd852019-10-31 07:42:51 -060054 return open(self.GetPath(fname), encoding='utf-8').read()
Simon Glass6e87ae12017-05-29 15:31:31 -060055
56 @classmethod
57 def GetPatchName(self, subject):
58 fname = re.sub('[ :]', '-', subject)
59 return fname.replace('--', '-')
60
61 def CreatePatchesForTest(self, series):
62 cover_fname = None
63 fname_list = []
64 for i, commit in enumerate(series.commits):
65 clean_subject = self.GetPatchName(commit.subject)
66 src_fname = '%04d-%s.patch' % (i + 1, clean_subject[:52])
67 fname = os.path.join(self.tmpdir, src_fname)
68 shutil.copy(self.GetPath(src_fname), fname)
69 fname_list.append(fname)
70 if series.get('cover'):
71 src_fname = '0000-cover-letter.patch'
72 cover_fname = os.path.join(self.tmpdir, src_fname)
73 fname = os.path.join(self.tmpdir, src_fname)
74 shutil.copy(self.GetPath(src_fname), fname)
75
76 return cover_fname, fname_list
77
78 def testBasic(self):
79 """Tests the basic flow of patman
80
81 This creates a series from some hard-coded patches build from a simple
82 tree with the following metadata in the top commit:
83
84 Series-to: u-boot
85 Series-prefix: RFC
86 Series-cc: Stefan Brüns <stefan.bruens@rwth-aachen.de>
87 Cover-letter-cc: Lord Mëlchett <clergy@palace.gov>
88 Series-version: 2
89 Series-changes: 4
90 - Some changes
91
92 Cover-letter:
93 test: A test patch series
94 This is a test of how the cover
95 leter
96 works
97 END
98
99 and this in the first commit:
100
101 Series-notes:
102 some notes
103 about some things
104 from the first commit
105 END
106
107 Commit-notes:
108 Some notes about
109 the first commit
110 END
111
112 with the following commands:
113
114 git log -n2 --reverse >/path/to/tools/patman/test/test01.txt
115 git format-patch --subject-prefix RFC --cover-letter HEAD~2
116 mv 00* /path/to/tools/patman/test
117
118 It checks these aspects:
119 - git log can be processed by patchstream
120 - emailing patches uses the correct command
121 - CC file has information on each commit
122 - cover letter has the expected text and subject
123 - each patch has the correct subject
124 - dry-run information prints out correctly
125 - unicode is handled correctly
126 - Series-to, Series-cc, Series-prefix, Cover-letter
127 - Cover-letter-cc, Series-version, Series-changes, Series-notes
128 - Commit-notes
129 """
130 process_tags = True
131 ignore_bad_tags = True
Simon Glasse6dca5e2019-05-14 15:53:53 -0600132 stefan = b'Stefan Br\xc3\xbcns <stefan.bruens@rwth-aachen.de>'.decode('utf-8')
Simon Glass6e87ae12017-05-29 15:31:31 -0600133 rick = 'Richard III <richard@palace.gov>'
Simon Glasse6dca5e2019-05-14 15:53:53 -0600134 mel = b'Lord M\xc3\xablchett <clergy@palace.gov>'.decode('utf-8')
135 ed = b'Lond Edmund Blackadd\xc3\xabr <weasel@blackadder.org'.decode('utf-8')
Simon Glass6e87ae12017-05-29 15:31:31 -0600136 fred = 'Fred Bloggs <f.bloggs@napier.net>'
137 add_maintainers = [stefan, rick]
138 dry_run = True
139 in_reply_to = mel
140 count = 2
141 settings.alias = {
142 'fdt': ['simon'],
143 'u-boot': ['u-boot@lists.denx.de'],
144 'simon': [ed],
145 'fred': [fred],
146 }
147
148 text = self.GetText('test01.txt')
149 series = patchstream.GetMetaDataForTest(text)
150 cover_fname, args = self.CreatePatchesForTest(series)
151 with capture() as out:
152 patchstream.FixPatches(series, args)
153 if cover_fname and series.get('cover'):
154 patchstream.InsertCoverLetter(cover_fname, series, count)
155 series.DoChecks()
156 cc_file = series.MakeCcFile(process_tags, cover_fname,
Chris Packham4fb35022018-06-07 20:45:06 +1200157 not ignore_bad_tags, add_maintainers,
158 None)
Simon Glass6e87ae12017-05-29 15:31:31 -0600159 cmd = gitutil.EmailPatches(series, cover_fname, args,
160 dry_run, not ignore_bad_tags, cc_file,
161 in_reply_to=in_reply_to, thread=None)
162 series.ShowActions(args, cmd, process_tags)
Simon Glass272cd852019-10-31 07:42:51 -0600163 cc_lines = open(cc_file, encoding='utf-8').read().splitlines()
Simon Glass6e87ae12017-05-29 15:31:31 -0600164 os.remove(cc_file)
165
166 lines = out[0].splitlines()
Simon Glass6e87ae12017-05-29 15:31:31 -0600167 self.assertEqual('Cleaned %s patches' % len(series.commits), lines[0])
168 self.assertEqual('Change log missing for v2', lines[1])
169 self.assertEqual('Change log missing for v3', lines[2])
170 self.assertEqual('Change log for unknown version v4', lines[3])
171 self.assertEqual("Alias 'pci' not found", lines[4])
172 self.assertIn('Dry run', lines[5])
173 self.assertIn('Send a total of %d patches' % count, lines[7])
174 line = 8
175 for i, commit in enumerate(series.commits):
176 self.assertEqual(' %s' % args[i], lines[line + 0])
177 line += 1
178 while 'Cc:' in lines[line]:
179 line += 1
180 self.assertEqual('To: u-boot@lists.denx.de', lines[line])
Simon Glasse6dca5e2019-05-14 15:53:53 -0600181 self.assertEqual('Cc: %s' % tools.FromUnicode(stefan),
182 lines[line + 1])
Simon Glass6e87ae12017-05-29 15:31:31 -0600183 self.assertEqual('Version: 3', lines[line + 2])
184 self.assertEqual('Prefix:\t RFC', lines[line + 3])
185 self.assertEqual('Cover: 4 lines', lines[line + 4])
186 line += 5
Simon Glassb644c662019-05-14 15:53:51 -0600187 self.assertEqual(' Cc: %s' % fred, lines[line + 0])
Simon Glasse6dca5e2019-05-14 15:53:53 -0600188 self.assertEqual(' Cc: %s' % tools.FromUnicode(ed),
189 lines[line + 1])
190 self.assertEqual(' Cc: %s' % tools.FromUnicode(mel),
191 lines[line + 2])
Simon Glassb644c662019-05-14 15:53:51 -0600192 self.assertEqual(' Cc: %s' % rick, lines[line + 3])
Simon Glass6e87ae12017-05-29 15:31:31 -0600193 expected = ('Git command: git send-email --annotate '
194 '--in-reply-to="%s" --to "u-boot@lists.denx.de" '
195 '--cc "%s" --cc-cmd "%s --cc-cmd %s" %s %s'
196 % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname,
Simon Glasse6dca5e2019-05-14 15:53:53 -0600197 ' '.join(args)))
Simon Glass6e87ae12017-05-29 15:31:31 -0600198 line += 4
Simon Glasse6dca5e2019-05-14 15:53:53 -0600199 self.assertEqual(expected, tools.ToUnicode(lines[line]))
Simon Glass6e87ae12017-05-29 15:31:31 -0600200
Dmitry Torokhov8ab452d2019-10-21 20:09:56 -0700201 self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)),
Simon Glasse6dca5e2019-05-14 15:53:53 -0600202 tools.ToUnicode(cc_lines[0]))
Dmitry Torokhov8ab452d2019-10-21 20:09:56 -0700203 self.assertEqual(('%s %s\0%s\0%s\0%s' % (args[1], fred, ed, rick,
Simon Glasse6dca5e2019-05-14 15:53:53 -0600204 stefan)), tools.ToUnicode(cc_lines[1]))
Simon Glass6e87ae12017-05-29 15:31:31 -0600205
206 expected = '''
207This is a test of how the cover
208leter
209works
210
211some notes
212about some things
213from the first commit
214
215Changes in v4:
216- Some changes
217
218Simon Glass (2):
219 pci: Correct cast for sandbox
Siva Durga Prasad Paladugu12308b12018-07-16 15:56:11 +0530220 fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base()
Simon Glass6e87ae12017-05-29 15:31:31 -0600221
222 cmd/pci.c | 3 ++-
223 fs/fat/fat.c | 1 +
224 lib/efi_loader/efi_memory.c | 1 +
225 lib/fdtdec.c | 3 ++-
226 4 files changed, 6 insertions(+), 2 deletions(-)
227
228--\x20
2292.7.4
230
231'''
Simon Glass272cd852019-10-31 07:42:51 -0600232 lines = open(cover_fname, encoding='utf-8').read().splitlines()
Simon Glass6e87ae12017-05-29 15:31:31 -0600233 self.assertEqual(
234 'Subject: [RFC PATCH v3 0/2] test: A test patch series',
235 lines[3])
236 self.assertEqual(expected.splitlines(), lines[7:])
237
238 for i, fname in enumerate(args):
Simon Glass272cd852019-10-31 07:42:51 -0600239 lines = open(fname, encoding='utf-8').read().splitlines()
Simon Glass6e87ae12017-05-29 15:31:31 -0600240 subject = [line for line in lines if line.startswith('Subject')]
241 self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count),
242 subject[0][:18])
243 if i == 0:
244 # Check that we got our commit notes
245 self.assertEqual('---', lines[17])
246 self.assertEqual('Some notes about', lines[18])
247 self.assertEqual('the first commit', lines[19])