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