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