b7e2825de88148c6b577519ded479e40987ac337
[platform/kernel/u-boot.git] / tools / patman / func_test.py
1 # -*- coding: utf-8 -*-
2 # SPDX-License-Identifier:      GPL-2.0+
3 #
4 # Copyright 2017 Google, Inc
5 #
6
7 import contextlib
8 import os
9 import re
10 import shutil
11 import sys
12 import tempfile
13 import unittest
14
15 from io import StringIO
16
17 from patman import gitutil
18 from patman import patchstream
19 from patman import settings
20 from patman import tools
21
22
23 @contextlib.contextmanager
24 def capture():
25     import sys
26     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
37 class 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):
51         return open(self.GetPath(fname), encoding='utf-8').read()
52
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>
85             Series-version: 2
86             Series-changes: 4
87             - Some changes
88
89             Cover-letter:
90             test: A test patch series
91             This is a test of how the cover
92             leter
93             works
94             END
95
96         and this in the first commit:
97
98             Series-notes:
99             some notes
100             about some things
101             from the first commit
102             END
103
104             Commit-notes:
105             Some notes about
106             the first commit
107             END
108
109         with the following commands:
110
111            git log -n2 --reverse >/path/to/tools/patman/test/test01.txt
112            git format-patch --subject-prefix RFC --cover-letter HEAD~2
113            mv 00* /path/to/tools/patman/test
114
115         It checks these aspects:
116             - git log can be processed by patchstream
117             - emailing patches uses the correct command
118             - CC file has information on each commit
119             - cover letter has the expected text and subject
120             - each patch has the correct subject
121             - dry-run information prints out correctly
122             - unicode is handled correctly
123             - Series-to, Series-cc, Series-prefix, Cover-letter
124             - Cover-letter-cc, Series-version, Series-changes, Series-notes
125             - Commit-notes
126         """
127         process_tags = True
128         ignore_bad_tags = True
129         stefan = b'Stefan Br\xc3\xbcns <stefan.bruens@rwth-aachen.de>'.decode('utf-8')
130         rick = 'Richard III <richard@palace.gov>'
131         mel = b'Lord M\xc3\xablchett <clergy@palace.gov>'.decode('utf-8')
132         ed = b'Lond Edmund Blackadd\xc3\xabr <weasel@blackadder.org'.decode('utf-8')
133         fred = 'Fred Bloggs <f.bloggs@napier.net>'
134         add_maintainers = [stefan, rick]
135         dry_run = True
136         in_reply_to = mel
137         count = 2
138         settings.alias = {
139                 'fdt': ['simon'],
140                 'u-boot': ['u-boot@lists.denx.de'],
141                 'simon': [ed],
142                 'fred': [fred],
143         }
144
145         text = self.GetText('test01.txt')
146         series = patchstream.GetMetaDataForTest(text)
147         cover_fname, args = self.CreatePatchesForTest(series)
148         with capture() as out:
149             patchstream.FixPatches(series, args)
150             if cover_fname and series.get('cover'):
151                 patchstream.InsertCoverLetter(cover_fname, series, count)
152             series.DoChecks()
153             cc_file = series.MakeCcFile(process_tags, cover_fname,
154                                         not ignore_bad_tags, add_maintainers,
155                                         None)
156             cmd = gitutil.EmailPatches(series, cover_fname, args,
157                     dry_run, not ignore_bad_tags, cc_file,
158                     in_reply_to=in_reply_to, thread=None)
159             series.ShowActions(args, cmd, process_tags)
160         cc_lines = open(cc_file, encoding='utf-8').read().splitlines()
161         os.remove(cc_file)
162
163         lines = out[0].splitlines()
164         self.assertEqual('Cleaned %s patches' % len(series.commits), lines[0])
165         self.assertEqual('Change log missing for v2', lines[1])
166         self.assertEqual('Change log missing for v3', lines[2])
167         self.assertEqual('Change log for unknown version v4', lines[3])
168         self.assertEqual("Alias 'pci' not found", lines[4])
169         self.assertIn('Dry run', lines[5])
170         self.assertIn('Send a total of %d patches' % count, lines[7])
171         line = 8
172         for i, commit in enumerate(series.commits):
173             self.assertEqual('   %s' % args[i], lines[line + 0])
174             line += 1
175             while 'Cc:' in lines[line]:
176                 line += 1
177         self.assertEqual('To:     u-boot@lists.denx.de', lines[line])
178         self.assertEqual('Cc:     %s' % tools.FromUnicode(stefan),
179                          lines[line + 1])
180         self.assertEqual('Version:  3', lines[line + 2])
181         self.assertEqual('Prefix:\t  RFC', lines[line + 3])
182         self.assertEqual('Cover: 4 lines', lines[line + 4])
183         line += 5
184         self.assertEqual('      Cc:  %s' % fred, lines[line + 0])
185         self.assertEqual('      Cc:  %s' % tools.FromUnicode(ed),
186                          lines[line + 1])
187         self.assertEqual('      Cc:  %s' % tools.FromUnicode(mel),
188                          lines[line + 2])
189         self.assertEqual('      Cc:  %s' % rick, lines[line + 3])
190         expected = ('Git command: git send-email --annotate '
191                     '--in-reply-to="%s" --to "u-boot@lists.denx.de" '
192                     '--cc "%s" --cc-cmd "%s --cc-cmd %s" %s %s'
193                     % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname,
194                        ' '.join(args)))
195         line += 4
196         self.assertEqual(expected, tools.ToUnicode(lines[line]))
197
198         self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)),
199                          tools.ToUnicode(cc_lines[0]))
200         self.assertEqual(('%s %s\0%s\0%s\0%s' % (args[1], fred, ed, rick,
201                                      stefan)), tools.ToUnicode(cc_lines[1]))
202
203         expected = '''
204 This is a test of how the cover
205 leter
206 works
207
208 some notes
209 about some things
210 from the first commit
211
212 Changes in v4:
213 - Some changes
214
215 Simon Glass (2):
216   pci: Correct cast for sandbox
217   fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base()
218
219  cmd/pci.c                   | 3 ++-
220  fs/fat/fat.c                | 1 +
221  lib/efi_loader/efi_memory.c | 1 +
222  lib/fdtdec.c                | 3 ++-
223  4 files changed, 6 insertions(+), 2 deletions(-)
224
225 --\x20
226 2.7.4
227
228 '''
229         lines = open(cover_fname, encoding='utf-8').read().splitlines()
230         self.assertEqual(
231                 'Subject: [RFC PATCH v3 0/2] test: A test patch series',
232                 lines[3])
233         self.assertEqual(expected.splitlines(), lines[7:])
234
235         for i, fname in enumerate(args):
236             lines = open(fname, encoding='utf-8').read().splitlines()
237             subject = [line for line in lines if line.startswith('Subject')]
238             self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count),
239                              subject[0][:18])
240             if i == 0:
241                 # Check that we got our commit notes
242                 self.assertEqual('---', lines[17])
243                 self.assertEqual('Some notes about', lines[18])
244                 self.assertEqual('the first commit', lines[19])