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