16e87ae1cSSimon Glass# -*- coding: utf-8 -*- 283d290c5STom Rini# SPDX-License-Identifier: GPL-2.0+ 36e87ae1cSSimon Glass# 46e87ae1cSSimon Glass# Copyright 2017 Google, Inc 56e87ae1cSSimon Glass# 66e87ae1cSSimon Glass 76e87ae1cSSimon Glassimport contextlib 86e87ae1cSSimon Glassimport os 96e87ae1cSSimon Glassimport re 106e87ae1cSSimon Glassimport shutil 116e87ae1cSSimon Glassimport sys 126e87ae1cSSimon Glassimport tempfile 136e87ae1cSSimon Glassimport unittest 146e87ae1cSSimon Glass 156e87ae1cSSimon Glassimport gitutil 166e87ae1cSSimon Glassimport patchstream 176e87ae1cSSimon Glassimport settings 186e87ae1cSSimon Glass 196e87ae1cSSimon Glass 206e87ae1cSSimon Glass@contextlib.contextmanager 216e87ae1cSSimon Glassdef capture(): 226e87ae1cSSimon Glass import sys 236e87ae1cSSimon Glass from cStringIO import StringIO 246e87ae1cSSimon Glass oldout,olderr = sys.stdout, sys.stderr 256e87ae1cSSimon Glass try: 266e87ae1cSSimon Glass out=[StringIO(), StringIO()] 276e87ae1cSSimon Glass sys.stdout,sys.stderr = out 286e87ae1cSSimon Glass yield out 296e87ae1cSSimon Glass finally: 306e87ae1cSSimon Glass sys.stdout,sys.stderr = oldout, olderr 316e87ae1cSSimon Glass out[0] = out[0].getvalue() 326e87ae1cSSimon Glass out[1] = out[1].getvalue() 336e87ae1cSSimon Glass 346e87ae1cSSimon Glass 356e87ae1cSSimon Glassclass TestFunctional(unittest.TestCase): 366e87ae1cSSimon Glass def setUp(self): 376e87ae1cSSimon Glass self.tmpdir = tempfile.mkdtemp(prefix='patman.') 386e87ae1cSSimon Glass 396e87ae1cSSimon Glass def tearDown(self): 406e87ae1cSSimon Glass shutil.rmtree(self.tmpdir) 416e87ae1cSSimon Glass 426e87ae1cSSimon Glass @staticmethod 436e87ae1cSSimon Glass def GetPath(fname): 446e87ae1cSSimon Glass return os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), 456e87ae1cSSimon Glass 'test', fname) 466e87ae1cSSimon Glass 476e87ae1cSSimon Glass @classmethod 486e87ae1cSSimon Glass def GetText(self, fname): 496e87ae1cSSimon Glass return open(self.GetPath(fname)).read() 506e87ae1cSSimon Glass 516e87ae1cSSimon Glass @classmethod 526e87ae1cSSimon Glass def GetPatchName(self, subject): 536e87ae1cSSimon Glass fname = re.sub('[ :]', '-', subject) 546e87ae1cSSimon Glass return fname.replace('--', '-') 556e87ae1cSSimon Glass 566e87ae1cSSimon Glass def CreatePatchesForTest(self, series): 576e87ae1cSSimon Glass cover_fname = None 586e87ae1cSSimon Glass fname_list = [] 596e87ae1cSSimon Glass for i, commit in enumerate(series.commits): 606e87ae1cSSimon Glass clean_subject = self.GetPatchName(commit.subject) 616e87ae1cSSimon Glass src_fname = '%04d-%s.patch' % (i + 1, clean_subject[:52]) 626e87ae1cSSimon Glass fname = os.path.join(self.tmpdir, src_fname) 636e87ae1cSSimon Glass shutil.copy(self.GetPath(src_fname), fname) 646e87ae1cSSimon Glass fname_list.append(fname) 656e87ae1cSSimon Glass if series.get('cover'): 666e87ae1cSSimon Glass src_fname = '0000-cover-letter.patch' 676e87ae1cSSimon Glass cover_fname = os.path.join(self.tmpdir, src_fname) 686e87ae1cSSimon Glass fname = os.path.join(self.tmpdir, src_fname) 696e87ae1cSSimon Glass shutil.copy(self.GetPath(src_fname), fname) 706e87ae1cSSimon Glass 716e87ae1cSSimon Glass return cover_fname, fname_list 726e87ae1cSSimon Glass 736e87ae1cSSimon Glass def testBasic(self): 746e87ae1cSSimon Glass """Tests the basic flow of patman 756e87ae1cSSimon Glass 766e87ae1cSSimon Glass This creates a series from some hard-coded patches build from a simple 776e87ae1cSSimon Glass tree with the following metadata in the top commit: 786e87ae1cSSimon Glass 796e87ae1cSSimon Glass Series-to: u-boot 806e87ae1cSSimon Glass Series-prefix: RFC 816e87ae1cSSimon Glass Series-cc: Stefan Brüns <stefan.bruens@rwth-aachen.de> 826e87ae1cSSimon Glass Cover-letter-cc: Lord Mëlchett <clergy@palace.gov> 836e87ae1cSSimon Glass Series-version: 2 846e87ae1cSSimon Glass Series-changes: 4 856e87ae1cSSimon Glass - Some changes 866e87ae1cSSimon Glass 876e87ae1cSSimon Glass Cover-letter: 886e87ae1cSSimon Glass test: A test patch series 896e87ae1cSSimon Glass This is a test of how the cover 906e87ae1cSSimon Glass leter 916e87ae1cSSimon Glass works 926e87ae1cSSimon Glass END 936e87ae1cSSimon Glass 946e87ae1cSSimon Glass and this in the first commit: 956e87ae1cSSimon Glass 966e87ae1cSSimon Glass Series-notes: 976e87ae1cSSimon Glass some notes 986e87ae1cSSimon Glass about some things 996e87ae1cSSimon Glass from the first commit 1006e87ae1cSSimon Glass END 1016e87ae1cSSimon Glass 1026e87ae1cSSimon Glass Commit-notes: 1036e87ae1cSSimon Glass Some notes about 1046e87ae1cSSimon Glass the first commit 1056e87ae1cSSimon Glass END 1066e87ae1cSSimon Glass 1076e87ae1cSSimon Glass with the following commands: 1086e87ae1cSSimon Glass 1096e87ae1cSSimon Glass git log -n2 --reverse >/path/to/tools/patman/test/test01.txt 1106e87ae1cSSimon Glass git format-patch --subject-prefix RFC --cover-letter HEAD~2 1116e87ae1cSSimon Glass mv 00* /path/to/tools/patman/test 1126e87ae1cSSimon Glass 1136e87ae1cSSimon Glass It checks these aspects: 1146e87ae1cSSimon Glass - git log can be processed by patchstream 1156e87ae1cSSimon Glass - emailing patches uses the correct command 1166e87ae1cSSimon Glass - CC file has information on each commit 1176e87ae1cSSimon Glass - cover letter has the expected text and subject 1186e87ae1cSSimon Glass - each patch has the correct subject 1196e87ae1cSSimon Glass - dry-run information prints out correctly 1206e87ae1cSSimon Glass - unicode is handled correctly 1216e87ae1cSSimon Glass - Series-to, Series-cc, Series-prefix, Cover-letter 1226e87ae1cSSimon Glass - Cover-letter-cc, Series-version, Series-changes, Series-notes 1236e87ae1cSSimon Glass - Commit-notes 1246e87ae1cSSimon Glass """ 1256e87ae1cSSimon Glass process_tags = True 1266e87ae1cSSimon Glass ignore_bad_tags = True 1276e87ae1cSSimon Glass stefan = u'Stefan Brüns <stefan.bruens@rwth-aachen.de>' 1286e87ae1cSSimon Glass rick = 'Richard III <richard@palace.gov>' 1296e87ae1cSSimon Glass mel = u'Lord Mëlchett <clergy@palace.gov>' 1306e87ae1cSSimon Glass ed = u'Lond Edmund Blackaddër <weasel@blackadder.org' 1316e87ae1cSSimon Glass fred = 'Fred Bloggs <f.bloggs@napier.net>' 1326e87ae1cSSimon Glass add_maintainers = [stefan, rick] 1336e87ae1cSSimon Glass dry_run = True 1346e87ae1cSSimon Glass in_reply_to = mel 1356e87ae1cSSimon Glass count = 2 1366e87ae1cSSimon Glass settings.alias = { 1376e87ae1cSSimon Glass 'fdt': ['simon'], 1386e87ae1cSSimon Glass 'u-boot': ['u-boot@lists.denx.de'], 1396e87ae1cSSimon Glass 'simon': [ed], 1406e87ae1cSSimon Glass 'fred': [fred], 1416e87ae1cSSimon Glass } 1426e87ae1cSSimon Glass 1436e87ae1cSSimon Glass text = self.GetText('test01.txt') 1446e87ae1cSSimon Glass series = patchstream.GetMetaDataForTest(text) 1456e87ae1cSSimon Glass cover_fname, args = self.CreatePatchesForTest(series) 1466e87ae1cSSimon Glass with capture() as out: 1476e87ae1cSSimon Glass patchstream.FixPatches(series, args) 1486e87ae1cSSimon Glass if cover_fname and series.get('cover'): 1496e87ae1cSSimon Glass patchstream.InsertCoverLetter(cover_fname, series, count) 1506e87ae1cSSimon Glass series.DoChecks() 1516e87ae1cSSimon Glass cc_file = series.MakeCcFile(process_tags, cover_fname, 1524fb35029SChris Packham not ignore_bad_tags, add_maintainers, 1534fb35029SChris Packham None) 1546e87ae1cSSimon Glass cmd = gitutil.EmailPatches(series, cover_fname, args, 1556e87ae1cSSimon Glass dry_run, not ignore_bad_tags, cc_file, 1566e87ae1cSSimon Glass in_reply_to=in_reply_to, thread=None) 1576e87ae1cSSimon Glass series.ShowActions(args, cmd, process_tags) 1586e87ae1cSSimon Glass cc_lines = open(cc_file).read().splitlines() 1596e87ae1cSSimon Glass os.remove(cc_file) 1606e87ae1cSSimon Glass 1616e87ae1cSSimon Glass lines = out[0].splitlines() 1626e87ae1cSSimon Glass #print '\n'.join(lines) 1636e87ae1cSSimon Glass self.assertEqual('Cleaned %s patches' % len(series.commits), lines[0]) 1646e87ae1cSSimon Glass self.assertEqual('Change log missing for v2', lines[1]) 1656e87ae1cSSimon Glass self.assertEqual('Change log missing for v3', lines[2]) 1666e87ae1cSSimon Glass self.assertEqual('Change log for unknown version v4', lines[3]) 1676e87ae1cSSimon Glass self.assertEqual("Alias 'pci' not found", lines[4]) 1686e87ae1cSSimon Glass self.assertIn('Dry run', lines[5]) 1696e87ae1cSSimon Glass self.assertIn('Send a total of %d patches' % count, lines[7]) 1706e87ae1cSSimon Glass line = 8 1716e87ae1cSSimon Glass for i, commit in enumerate(series.commits): 1726e87ae1cSSimon Glass self.assertEqual(' %s' % args[i], lines[line + 0]) 1736e87ae1cSSimon Glass line += 1 1746e87ae1cSSimon Glass while 'Cc:' in lines[line]: 1756e87ae1cSSimon Glass line += 1 1766e87ae1cSSimon Glass self.assertEqual('To: u-boot@lists.denx.de', lines[line]) 1776e87ae1cSSimon Glass self.assertEqual('Cc: %s' % stefan.encode('utf-8'), lines[line + 1]) 1786e87ae1cSSimon Glass self.assertEqual('Version: 3', lines[line + 2]) 1796e87ae1cSSimon Glass self.assertEqual('Prefix:\t RFC', lines[line + 3]) 1806e87ae1cSSimon Glass self.assertEqual('Cover: 4 lines', lines[line + 4]) 1816e87ae1cSSimon Glass line += 5 1826e87ae1cSSimon Glass self.assertEqual(' Cc: %s' % mel.encode('utf-8'), lines[line + 0]) 1836e87ae1cSSimon Glass self.assertEqual(' Cc: %s' % rick, lines[line + 1]) 1846e87ae1cSSimon Glass self.assertEqual(' Cc: %s' % fred, lines[line + 2]) 1856e87ae1cSSimon Glass self.assertEqual(' Cc: %s' % ed.encode('utf-8'), lines[line + 3]) 1866e87ae1cSSimon Glass expected = ('Git command: git send-email --annotate ' 1876e87ae1cSSimon Glass '--in-reply-to="%s" --to "u-boot@lists.denx.de" ' 1886e87ae1cSSimon Glass '--cc "%s" --cc-cmd "%s --cc-cmd %s" %s %s' 1896e87ae1cSSimon Glass % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname, 1906e87ae1cSSimon Glass ' '.join(args))).encode('utf-8') 1916e87ae1cSSimon Glass line += 4 1926e87ae1cSSimon Glass self.assertEqual(expected, lines[line]) 1936e87ae1cSSimon Glass 1946e87ae1cSSimon Glass self.assertEqual(('%s %s, %s' % (args[0], rick, stefan)) 1956e87ae1cSSimon Glass .encode('utf-8'), cc_lines[0]) 1966e87ae1cSSimon Glass self.assertEqual(('%s %s, %s, %s, %s' % (args[1], fred, rick, stefan, 1976e87ae1cSSimon Glass ed)).encode('utf-8'), cc_lines[1]) 1986e87ae1cSSimon Glass 1996e87ae1cSSimon Glass expected = ''' 2006e87ae1cSSimon GlassThis is a test of how the cover 2016e87ae1cSSimon Glassleter 2026e87ae1cSSimon Glassworks 2036e87ae1cSSimon Glass 2046e87ae1cSSimon Glasssome notes 2056e87ae1cSSimon Glassabout some things 2066e87ae1cSSimon Glassfrom the first commit 2076e87ae1cSSimon Glass 2086e87ae1cSSimon GlassChanges in v4: 2096e87ae1cSSimon Glass- Some changes 2106e87ae1cSSimon Glass 2116e87ae1cSSimon GlassSimon Glass (2): 2126e87ae1cSSimon Glass pci: Correct cast for sandbox 213*12308b12SSiva Durga Prasad Paladugu fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base() 2146e87ae1cSSimon Glass 2156e87ae1cSSimon Glass cmd/pci.c | 3 ++- 2166e87ae1cSSimon Glass fs/fat/fat.c | 1 + 2176e87ae1cSSimon Glass lib/efi_loader/efi_memory.c | 1 + 2186e87ae1cSSimon Glass lib/fdtdec.c | 3 ++- 2196e87ae1cSSimon Glass 4 files changed, 6 insertions(+), 2 deletions(-) 2206e87ae1cSSimon Glass 2216e87ae1cSSimon Glass--\x20 2226e87ae1cSSimon Glass2.7.4 2236e87ae1cSSimon Glass 2246e87ae1cSSimon Glass''' 2256e87ae1cSSimon Glass lines = open(cover_fname).read().splitlines() 2266e87ae1cSSimon Glass #print '\n'.join(lines) 2276e87ae1cSSimon Glass self.assertEqual( 2286e87ae1cSSimon Glass 'Subject: [RFC PATCH v3 0/2] test: A test patch series', 2296e87ae1cSSimon Glass lines[3]) 2306e87ae1cSSimon Glass self.assertEqual(expected.splitlines(), lines[7:]) 2316e87ae1cSSimon Glass 2326e87ae1cSSimon Glass for i, fname in enumerate(args): 2336e87ae1cSSimon Glass lines = open(fname).read().splitlines() 2346e87ae1cSSimon Glass #print '\n'.join(lines) 2356e87ae1cSSimon Glass subject = [line for line in lines if line.startswith('Subject')] 2366e87ae1cSSimon Glass self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count), 2376e87ae1cSSimon Glass subject[0][:18]) 2386e87ae1cSSimon Glass if i == 0: 2396e87ae1cSSimon Glass # Check that we got our commit notes 2406e87ae1cSSimon Glass self.assertEqual('---', lines[17]) 2416e87ae1cSSimon Glass self.assertEqual('Some notes about', lines[18]) 2426e87ae1cSSimon Glass self.assertEqual('the first commit', lines[19]) 243