blob: 74a144dc2d5a2ce35d747df98fa8479917c9b2db [file] [log] [blame]
Simon Glassdf1bc5c2017-05-29 15:31:31 -06001# -*- coding: utf-8 -*-
Tom Rini10e47792018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glassdf1bc5c2017-05-29 15:31:31 -06003#
4# Copyright 2017 Google, Inc
5#
Simon Glassdf1bc5c2017-05-29 15:31:31 -06006
Simon Glasseb209e52020-10-29 21:46:15 -06007"""Functional tests for checking that patman behaves correctly"""
8
Simon Glassdf1bc5c2017-05-29 15:31:31 -06009import os
10import re
11import shutil
12import sys
13import tempfile
14import unittest
15
Simon Glass3db916d2020-10-29 21:46:35 -060016
17from patman.commit import Commit
Simon Glass54f1c5b2020-07-05 21:41:50 -060018from patman import control
Simon Glassa997ea52020-04-17 18:09:04 -060019from patman import gitutil
20from patman import patchstream
Simon Glassa7fadab2020-10-29 21:46:26 -060021from patman.patchstream import PatchStream
Simon Glass3db916d2020-10-29 21:46:35 -060022from patman.series import Series
Simon Glassa997ea52020-04-17 18:09:04 -060023from patman import settings
Simon Glass54f1c5b2020-07-05 21:41:50 -060024from patman import terminal
Simon Glassa997ea52020-04-17 18:09:04 -060025from patman import tools
Simon Glass54f1c5b2020-07-05 21:41:50 -060026from patman.test_util import capture_sys_output
Simon Glassdf1bc5c2017-05-29 15:31:31 -060027
Simon Glass54f1c5b2020-07-05 21:41:50 -060028try:
29 import pygit2
Simon Glass95745aa2020-10-29 21:46:13 -060030 HAVE_PYGIT2 = True
Simon Glass3db916d2020-10-29 21:46:35 -060031 from patman import status
Simon Glass54f1c5b2020-07-05 21:41:50 -060032except ModuleNotFoundError:
33 HAVE_PYGIT2 = False
34
Simon Glassdf1bc5c2017-05-29 15:31:31 -060035
36class TestFunctional(unittest.TestCase):
Simon Glasseb209e52020-10-29 21:46:15 -060037 """Functional tests for checking that patman behaves correctly"""
Simon Glass06202d62020-10-29 21:46:27 -060038 leb = (b'Lord Edmund Blackadd\xc3\xabr <weasel@blackadder.org>'.
39 decode('utf-8'))
Simon Glass3b762cc2020-10-29 21:46:28 -060040 fred = 'Fred Bloggs <f.bloggs@napier.net>'
41 joe = 'Joe Bloggs <joe@napierwallies.co.nz>'
42 mary = 'Mary Bloggs <mary@napierwallies.co.nz>'
Simon Glass3db916d2020-10-29 21:46:35 -060043 commits = None
44 patches = None
Simon Glass06202d62020-10-29 21:46:27 -060045
Simon Glassdf1bc5c2017-05-29 15:31:31 -060046 def setUp(self):
47 self.tmpdir = tempfile.mkdtemp(prefix='patman.')
Simon Glass54f1c5b2020-07-05 21:41:50 -060048 self.gitdir = os.path.join(self.tmpdir, 'git')
49 self.repo = None
Simon Glassdf1bc5c2017-05-29 15:31:31 -060050
51 def tearDown(self):
52 shutil.rmtree(self.tmpdir)
Simon Glass3db916d2020-10-29 21:46:35 -060053 terminal.SetPrintTestMode(False)
Simon Glassdf1bc5c2017-05-29 15:31:31 -060054
55 @staticmethod
Simon Glasseb209e52020-10-29 21:46:15 -060056 def _get_path(fname):
57 """Get the path to a test file
58
59 Args:
60 fname (str): Filename to obtain
61
62 Returns:
63 str: Full path to file in the test directory
64 """
Simon Glassdf1bc5c2017-05-29 15:31:31 -060065 return os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
66 'test', fname)
67
68 @classmethod
Simon Glasseb209e52020-10-29 21:46:15 -060069 def _get_text(cls, fname):
70 """Read a file as text
71
72 Args:
73 fname (str): Filename to read
74
75 Returns:
76 str: Contents of file
77 """
78 return open(cls._get_path(fname), encoding='utf-8').read()
Simon Glassdf1bc5c2017-05-29 15:31:31 -060079
80 @classmethod
Simon Glasseb209e52020-10-29 21:46:15 -060081 def _get_patch_name(cls, subject):
82 """Get the filename of a patch given its subject
83
84 Args:
85 subject (str): Patch subject
86
87 Returns:
88 str: Filename for that patch
89 """
Simon Glassdf1bc5c2017-05-29 15:31:31 -060090 fname = re.sub('[ :]', '-', subject)
91 return fname.replace('--', '-')
92
Simon Glasseb209e52020-10-29 21:46:15 -060093 def _create_patches_for_test(self, series):
94 """Create patch files for use by tests
95
96 This copies patch files from the test directory as needed by the series
97
98 Args:
99 series (Series): Series containing commits to convert
100
101 Returns:
102 tuple:
103 str: Cover-letter filename, or None if none
104 fname_list: list of str, each a patch filename
105 """
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600106 cover_fname = None
107 fname_list = []
108 for i, commit in enumerate(series.commits):
Simon Glasseb209e52020-10-29 21:46:15 -0600109 clean_subject = self._get_patch_name(commit.subject)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600110 src_fname = '%04d-%s.patch' % (i + 1, clean_subject[:52])
111 fname = os.path.join(self.tmpdir, src_fname)
Simon Glasseb209e52020-10-29 21:46:15 -0600112 shutil.copy(self._get_path(src_fname), fname)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600113 fname_list.append(fname)
114 if series.get('cover'):
115 src_fname = '0000-cover-letter.patch'
116 cover_fname = os.path.join(self.tmpdir, src_fname)
117 fname = os.path.join(self.tmpdir, src_fname)
Simon Glasseb209e52020-10-29 21:46:15 -0600118 shutil.copy(self._get_path(src_fname), fname)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600119
120 return cover_fname, fname_list
121
122 def testBasic(self):
123 """Tests the basic flow of patman
124
125 This creates a series from some hard-coded patches build from a simple
126 tree with the following metadata in the top commit:
127
128 Series-to: u-boot
129 Series-prefix: RFC
130 Series-cc: Stefan Brüns <stefan.bruens@rwth-aachen.de>
131 Cover-letter-cc: Lord Mëlchett <clergy@palace.gov>
Sean Andersoncf13b862020-05-04 16:28:36 -0400132 Series-version: 3
133 Patch-cc: fred
134 Series-process-log: sort, uniq
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600135 Series-changes: 4
136 - Some changes
Sean Andersoncf13b862020-05-04 16:28:36 -0400137 - Multi
138 line
139 change
140
141 Commit-changes: 2
142 - Changes only for this commit
143
144 Cover-changes: 4
145 - Some notes for the cover letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600146
147 Cover-letter:
148 test: A test patch series
149 This is a test of how the cover
Sean Andersoncf13b862020-05-04 16:28:36 -0400150 letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600151 works
152 END
153
154 and this in the first commit:
155
Sean Andersoncf13b862020-05-04 16:28:36 -0400156 Commit-changes: 2
157 - second revision change
158
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600159 Series-notes:
160 some notes
161 about some things
162 from the first commit
163 END
164
165 Commit-notes:
166 Some notes about
167 the first commit
168 END
169
170 with the following commands:
171
172 git log -n2 --reverse >/path/to/tools/patman/test/test01.txt
173 git format-patch --subject-prefix RFC --cover-letter HEAD~2
174 mv 00* /path/to/tools/patman/test
175
176 It checks these aspects:
177 - git log can be processed by patchstream
178 - emailing patches uses the correct command
179 - CC file has information on each commit
180 - cover letter has the expected text and subject
181 - each patch has the correct subject
182 - dry-run information prints out correctly
183 - unicode is handled correctly
184 - Series-to, Series-cc, Series-prefix, Cover-letter
185 - Cover-letter-cc, Series-version, Series-changes, Series-notes
186 - Commit-notes
187 """
188 process_tags = True
189 ignore_bad_tags = True
Simon Glass4f817892019-05-14 15:53:53 -0600190 stefan = b'Stefan Br\xc3\xbcns <stefan.bruens@rwth-aachen.de>'.decode('utf-8')
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600191 rick = 'Richard III <richard@palace.gov>'
Simon Glass4f817892019-05-14 15:53:53 -0600192 mel = b'Lord M\xc3\xablchett <clergy@palace.gov>'.decode('utf-8')
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600193 add_maintainers = [stefan, rick]
194 dry_run = True
195 in_reply_to = mel
196 count = 2
197 settings.alias = {
Simon Glass95745aa2020-10-29 21:46:13 -0600198 'fdt': ['simon'],
199 'u-boot': ['u-boot@lists.denx.de'],
Simon Glass06202d62020-10-29 21:46:27 -0600200 'simon': [self.leb],
Simon Glass3b762cc2020-10-29 21:46:28 -0600201 'fred': [self.fred],
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600202 }
203
Simon Glasseb209e52020-10-29 21:46:15 -0600204 text = self._get_text('test01.txt')
Simon Glass93f61c02020-10-29 21:46:19 -0600205 series = patchstream.get_metadata_for_test(text)
Simon Glasseb209e52020-10-29 21:46:15 -0600206 cover_fname, args = self._create_patches_for_test(series)
Simon Glass59a70bb2020-10-29 21:46:14 -0600207 with capture_sys_output() as out:
Simon Glass93f61c02020-10-29 21:46:19 -0600208 patchstream.fix_patches(series, args)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600209 if cover_fname and series.get('cover'):
Simon Glass93f61c02020-10-29 21:46:19 -0600210 patchstream.insert_cover_letter(cover_fname, series, count)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600211 series.DoChecks()
212 cc_file = series.MakeCcFile(process_tags, cover_fname,
Chris Packhamb84fb482018-06-07 20:45:06 +1200213 not ignore_bad_tags, add_maintainers,
214 None)
Simon Glass95745aa2020-10-29 21:46:13 -0600215 cmd = gitutil.EmailPatches(
216 series, cover_fname, args, dry_run, not ignore_bad_tags,
217 cc_file, in_reply_to=in_reply_to, thread=None)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600218 series.ShowActions(args, cmd, process_tags)
Simon Glassf544a2d2019-10-31 07:42:51 -0600219 cc_lines = open(cc_file, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600220 os.remove(cc_file)
221
Simon Glass42e3d392020-10-29 21:46:29 -0600222 lines = iter(out[0].getvalue().splitlines())
223 self.assertEqual('Cleaned %s patches' % len(series.commits),
224 next(lines))
225 self.assertEqual('Change log missing for v2', next(lines))
226 self.assertEqual('Change log missing for v3', next(lines))
227 self.assertEqual('Change log for unknown version v4', next(lines))
228 self.assertEqual("Alias 'pci' not found", next(lines))
229 self.assertIn('Dry run', next(lines))
230 self.assertEqual('', next(lines))
231 self.assertIn('Send a total of %d patches' % count, next(lines))
232 prev = next(lines)
233 for i, commit in enumerate(series.commits):
234 self.assertEqual(' %s' % args[i], prev)
235 while True:
236 prev = next(lines)
237 if 'Cc:' not in prev:
238 break
239 self.assertEqual('To: u-boot@lists.denx.de', prev)
240 self.assertEqual('Cc: %s' % tools.FromUnicode(stefan), next(lines))
241 self.assertEqual('Version: 3', next(lines))
242 self.assertEqual('Prefix:\t RFC', next(lines))
243 self.assertEqual('Cover: 4 lines', next(lines))
244 self.assertEqual(' Cc: %s' % self.fred, next(lines))
Simon Glass06202d62020-10-29 21:46:27 -0600245 self.assertEqual(' Cc: %s' % tools.FromUnicode(self.leb),
Simon Glass42e3d392020-10-29 21:46:29 -0600246 next(lines))
247 self.assertEqual(' Cc: %s' % tools.FromUnicode(mel), next(lines))
248 self.assertEqual(' Cc: %s' % rick, next(lines))
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600249 expected = ('Git command: git send-email --annotate '
250 '--in-reply-to="%s" --to "u-boot@lists.denx.de" '
Simon Glass1ee91c12020-11-03 13:54:10 -0700251 '--cc "%s" --cc-cmd "%s send --cc-cmd %s" %s %s'
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600252 % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname,
Simon Glass4f817892019-05-14 15:53:53 -0600253 ' '.join(args)))
Simon Glass42e3d392020-10-29 21:46:29 -0600254 self.assertEqual(expected, tools.ToUnicode(next(lines)))
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600255
Dmitry Torokhovef7f67d2019-10-21 20:09:56 -0700256 self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)),
Simon Glass4f817892019-05-14 15:53:53 -0600257 tools.ToUnicode(cc_lines[0]))
Simon Glass95745aa2020-10-29 21:46:13 -0600258 self.assertEqual(
Simon Glass3b762cc2020-10-29 21:46:28 -0600259 '%s %s\0%s\0%s\0%s' % (args[1], self.fred, self.leb, rick, stefan),
Simon Glass95745aa2020-10-29 21:46:13 -0600260 tools.ToUnicode(cc_lines[1]))
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600261
262 expected = '''
263This is a test of how the cover
Sean Andersoncf13b862020-05-04 16:28:36 -0400264letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600265works
266
267some notes
268about some things
269from the first commit
270
271Changes in v4:
Sean Andersoncf13b862020-05-04 16:28:36 -0400272- Multi
273 line
274 change
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600275- Some changes
Sean Andersoncf13b862020-05-04 16:28:36 -0400276- Some notes for the cover letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600277
278Simon Glass (2):
279 pci: Correct cast for sandbox
Siva Durga Prasad Paladugub3d55ea2018-07-16 15:56:11 +0530280 fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600281
282 cmd/pci.c | 3 ++-
283 fs/fat/fat.c | 1 +
284 lib/efi_loader/efi_memory.c | 1 +
285 lib/fdtdec.c | 3 ++-
286 4 files changed, 6 insertions(+), 2 deletions(-)
287
288--\x20
2892.7.4
290
291'''
Simon Glassf544a2d2019-10-31 07:42:51 -0600292 lines = open(cover_fname, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600293 self.assertEqual(
Simon Glass95745aa2020-10-29 21:46:13 -0600294 'Subject: [RFC PATCH v3 0/2] test: A test patch series',
295 lines[3])
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600296 self.assertEqual(expected.splitlines(), lines[7:])
297
298 for i, fname in enumerate(args):
Simon Glassf544a2d2019-10-31 07:42:51 -0600299 lines = open(fname, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600300 subject = [line for line in lines if line.startswith('Subject')]
301 self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count),
302 subject[0][:18])
Sean Andersoncf13b862020-05-04 16:28:36 -0400303
304 # Check that we got our commit notes
305 start = 0
306 expected = ''
307
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600308 if i == 0:
Sean Andersoncf13b862020-05-04 16:28:36 -0400309 start = 17
310 expected = '''---
311Some notes about
312the first commit
313
314(no changes since v2)
315
316Changes in v2:
317- second revision change'''
318 elif i == 1:
319 start = 17
320 expected = '''---
321
322Changes in v4:
323- Multi
324 line
325 change
326- Some changes
327
328Changes in v2:
329- Changes only for this commit'''
330
331 if expected:
332 expected = expected.splitlines()
333 self.assertEqual(expected, lines[start:(start+len(expected))])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600334
335 def make_commit_with_file(self, subject, body, fname, text):
336 """Create a file and add it to the git repo with a new commit
337
338 Args:
339 subject (str): Subject for the commit
340 body (str): Body text of the commit
341 fname (str): Filename of file to create
342 text (str): Text to put into the file
343 """
344 path = os.path.join(self.gitdir, fname)
345 tools.WriteFile(path, text, binary=False)
346 index = self.repo.index
347 index.add(fname)
Simon Glass95745aa2020-10-29 21:46:13 -0600348 author = pygit2.Signature('Test user', 'test@email.com')
Simon Glass54f1c5b2020-07-05 21:41:50 -0600349 committer = author
350 tree = index.write_tree()
351 message = subject + '\n' + body
352 self.repo.create_commit('HEAD', author, committer, message, tree,
353 [self.repo.head.target])
354
355 def make_git_tree(self):
356 """Make a simple git tree suitable for testing
357
358 It has three branches:
359 'base' has two commits: PCI, main
360 'first' has base as upstream and two more commits: I2C, SPI
361 'second' has base as upstream and three more: video, serial, bootm
362
363 Returns:
Simon Glasseb209e52020-10-29 21:46:15 -0600364 pygit2.Repository: repository
Simon Glass54f1c5b2020-07-05 21:41:50 -0600365 """
366 repo = pygit2.init_repository(self.gitdir)
367 self.repo = repo
368 new_tree = repo.TreeBuilder().write()
369
370 author = pygit2.Signature('Test user', 'test@email.com')
371 committer = author
Simon Glasseb209e52020-10-29 21:46:15 -0600372 _ = repo.create_commit('HEAD', author, committer, 'Created master',
373 new_tree, [])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600374
375 self.make_commit_with_file('Initial commit', '''
376Add a README
377
378''', 'README', '''This is the README file
379describing this project
380in very little detail''')
381
382 self.make_commit_with_file('pci: PCI implementation', '''
383Here is a basic PCI implementation
384
385''', 'pci.c', '''This is a file
386it has some contents
387and some more things''')
388 self.make_commit_with_file('main: Main program', '''
389Hello here is the second commit.
390''', 'main.c', '''This is the main file
391there is very little here
392but we can always add more later
393if we want to
394
395Series-to: u-boot
396Series-cc: Barry Crump <bcrump@whataroa.nz>
397''')
398 base_target = repo.revparse_single('HEAD')
399 self.make_commit_with_file('i2c: I2C things', '''
400This has some stuff to do with I2C
401''', 'i2c.c', '''And this is the file contents
402with some I2C-related things in it''')
403 self.make_commit_with_file('spi: SPI fixes', '''
404SPI needs some fixes
405and here they are
Simon Glassd0a0a582020-10-29 21:46:36 -0600406
407Signed-off-by: %s
408
409Series-to: u-boot
410Commit-notes:
411title of the series
412This is the cover letter for the series
413with various details
414END
415''' % self.leb, 'spi.c', '''Some fixes for SPI in this
Simon Glass54f1c5b2020-07-05 21:41:50 -0600416file to make SPI work
417better than before''')
418 first_target = repo.revparse_single('HEAD')
419
420 target = repo.revparse_single('HEAD~2')
421 repo.reset(target.oid, pygit2.GIT_CHECKOUT_FORCE)
422 self.make_commit_with_file('video: Some video improvements', '''
423Fix up the video so that
424it looks more purple. Purple is
425a very nice colour.
426''', 'video.c', '''More purple here
427Purple and purple
428Even more purple
429Could not be any more purple''')
430 self.make_commit_with_file('serial: Add a serial driver', '''
431Here is the serial driver
432for my chip.
433
434Cover-letter:
435Series for my board
436This series implements support
437for my glorious board.
438END
Simon Glassa80986c2020-10-29 21:46:16 -0600439Series-links: 183237
Simon Glass54f1c5b2020-07-05 21:41:50 -0600440''', 'serial.c', '''The code for the
441serial driver is here''')
442 self.make_commit_with_file('bootm: Make it boot', '''
443This makes my board boot
444with a fix to the bootm
445command
446''', 'bootm.c', '''Fix up the bootm
447command to make the code as
448complicated as possible''')
449 second_target = repo.revparse_single('HEAD')
450
451 repo.branches.local.create('first', first_target)
452 repo.config.set_multivar('branch.first.remote', '', '.')
453 repo.config.set_multivar('branch.first.merge', '', 'refs/heads/base')
454
455 repo.branches.local.create('second', second_target)
456 repo.config.set_multivar('branch.second.remote', '', '.')
457 repo.config.set_multivar('branch.second.merge', '', 'refs/heads/base')
458
459 repo.branches.local.create('base', base_target)
460 return repo
461
462 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
463 def testBranch(self):
464 """Test creating patches from a branch"""
465 repo = self.make_git_tree()
466 target = repo.lookup_reference('refs/heads/first')
467 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
468 control.setup()
469 try:
470 orig_dir = os.getcwd()
471 os.chdir(self.gitdir)
472
473 # Check that it can detect the current branch
Simon Glass2eb4da72020-07-05 21:41:51 -0600474 self.assertEqual(2, gitutil.CountCommitsToBranch(None))
Simon Glass54f1c5b2020-07-05 21:41:50 -0600475 col = terminal.Color()
476 with capture_sys_output() as _:
477 _, cover_fname, patch_files = control.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600478 col, branch=None, count=-1, start=0, end=0,
479 ignore_binary=False)
Simon Glass54f1c5b2020-07-05 21:41:50 -0600480 self.assertIsNone(cover_fname)
481 self.assertEqual(2, len(patch_files))
Simon Glass2eb4da72020-07-05 21:41:51 -0600482
483 # Check that it can detect a different branch
484 self.assertEqual(3, gitutil.CountCommitsToBranch('second'))
485 with capture_sys_output() as _:
486 _, cover_fname, patch_files = control.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600487 col, branch='second', count=-1, start=0, end=0,
Simon Glass2eb4da72020-07-05 21:41:51 -0600488 ignore_binary=False)
489 self.assertIsNotNone(cover_fname)
490 self.assertEqual(3, len(patch_files))
Simon Glassb3bf4e12020-07-05 21:41:52 -0600491
492 # Check that it can skip patches at the end
493 with capture_sys_output() as _:
494 _, cover_fname, patch_files = control.prepare_patches(
495 col, branch='second', count=-1, start=0, end=1,
496 ignore_binary=False)
497 self.assertIsNotNone(cover_fname)
498 self.assertEqual(2, len(patch_files))
Simon Glass54f1c5b2020-07-05 21:41:50 -0600499 finally:
500 os.chdir(orig_dir)
Simon Glass06202d62020-10-29 21:46:27 -0600501
502 def testTags(self):
503 """Test collection of tags in a patchstream"""
504 text = '''This is a patch
505
506Signed-off-by: Terminator
Simon Glass3b762cc2020-10-29 21:46:28 -0600507Reviewed-by: %s
508Reviewed-by: %s
Simon Glass06202d62020-10-29 21:46:27 -0600509Tested-by: %s
Simon Glass3b762cc2020-10-29 21:46:28 -0600510''' % (self.joe, self.mary, self.leb)
Simon Glass06202d62020-10-29 21:46:27 -0600511 pstrm = PatchStream.process_text(text)
512 self.assertEqual(pstrm.commit.rtags, {
Simon Glass3b762cc2020-10-29 21:46:28 -0600513 'Reviewed-by': {self.joe, self.mary},
Simon Glass06202d62020-10-29 21:46:27 -0600514 'Tested-by': {self.leb}})
Simon Glass3b762cc2020-10-29 21:46:28 -0600515
516 def testMissingEnd(self):
517 """Test a missing END tag"""
518 text = '''This is a patch
519
520Cover-letter:
521This is the title
522missing END after this line
523Signed-off-by: Fred
524'''
525 pstrm = PatchStream.process_text(text)
526 self.assertEqual(["Missing 'END' in section 'cover'"],
527 pstrm.commit.warn)
528
529 def testMissingBlankLine(self):
530 """Test a missing blank line after a tag"""
531 text = '''This is a patch
532
533Series-changes: 2
534- First line of changes
535- Missing blank line after this line
536Signed-off-by: Fred
537'''
538 pstrm = PatchStream.process_text(text)
539 self.assertEqual(["Missing 'blank line' in section 'Series-changes'"],
540 pstrm.commit.warn)
541
542 def testInvalidCommitTag(self):
543 """Test an invalid Commit-xxx tag"""
544 text = '''This is a patch
545
546Commit-fred: testing
547'''
548 pstrm = PatchStream.process_text(text)
549 self.assertEqual(["Line 3: Ignoring Commit-fred"], pstrm.commit.warn)
550
551 def testSelfTest(self):
552 """Test a tested by tag by this user"""
553 test_line = 'Tested-by: %s@napier.com' % os.getenv('USER')
554 text = '''This is a patch
555
556%s
557''' % test_line
558 pstrm = PatchStream.process_text(text)
559 self.assertEqual(["Ignoring '%s'" % test_line], pstrm.commit.warn)
560
561 def testSpaceBeforeTab(self):
562 """Test a space before a tab"""
563 text = '''This is a patch
564
565+ \tSomething
566'''
567 pstrm = PatchStream.process_text(text)
568 self.assertEqual(["Line 3/0 has space before tab"], pstrm.commit.warn)
569
570 def testLinesAfterTest(self):
571 """Test detecting lines after TEST= line"""
572 text = '''This is a patch
573
574TEST=sometest
575more lines
576here
577'''
578 pstrm = PatchStream.process_text(text)
579 self.assertEqual(["Found 2 lines after TEST="], pstrm.commit.warn)
580
581 def testBlankLineAtEnd(self):
582 """Test detecting a blank line at the end of a file"""
583 text = '''This is a patch
584
585diff --git a/lib/fdtdec.c b/lib/fdtdec.c
586index c072e54..942244f 100644
587--- a/lib/fdtdec.c
588+++ b/lib/fdtdec.c
589@@ -1200,7 +1200,8 @@ int fdtdec_setup_mem_size_base(void)
590 }
591
592 gd->ram_size = (phys_size_t)(res.end - res.start + 1);
593- debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size);
594+ debug("%s: Initial DRAM size %llx\n", __func__,
595+ (unsigned long long)gd->ram_size);
596+
597diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
598
599--
6002.7.4
601
602 '''
603 pstrm = PatchStream.process_text(text)
604 self.assertEqual(
605 ["Found possible blank line(s) at end of file 'lib/fdtdec.c'"],
606 pstrm.commit.warn)
Simon Glass1c1f2072020-10-29 21:46:34 -0600607
608 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
609 def testNoUpstream(self):
610 """Test CountCommitsToBranch when there is no upstream"""
611 repo = self.make_git_tree()
612 target = repo.lookup_reference('refs/heads/base')
613 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
614
615 # Check that it can detect the current branch
616 try:
617 orig_dir = os.getcwd()
618 os.chdir(self.gitdir)
619 with self.assertRaises(ValueError) as exc:
620 gitutil.CountCommitsToBranch(None)
621 self.assertIn(
622 "Failed to determine upstream: fatal: no upstream configured for branch 'base'",
623 str(exc.exception))
624 finally:
625 os.chdir(orig_dir)
Simon Glass3db916d2020-10-29 21:46:35 -0600626
627 @staticmethod
Simon Glassf9b03cf2020-11-03 13:54:14 -0700628 def _fake_patchwork(url, subpath):
Simon Glass3db916d2020-10-29 21:46:35 -0600629 """Fake Patchwork server for the function below
630
631 This handles accessing a series, providing a list consisting of a
632 single patch
Simon Glassf9b03cf2020-11-03 13:54:14 -0700633
634 Args:
635 url (str): URL of patchwork server
636 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600637 """
638 re_series = re.match(r'series/(\d*)/$', subpath)
639 if re_series:
640 series_num = re_series.group(1)
641 if series_num == '1234':
642 return {'patches': [
643 {'id': '1', 'name': 'Some patch'}]}
644 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
645
646 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
647 def testStatusMismatch(self):
648 """Test Patchwork patches not matching the series"""
649 series = Series()
650
651 with capture_sys_output() as (_, err):
Simon Glassf9b03cf2020-11-03 13:54:14 -0700652 status.collect_patches(series, 1234, None, self._fake_patchwork)
Simon Glass3db916d2020-10-29 21:46:35 -0600653 self.assertIn('Warning: Patchwork reports 1 patches, series has 0',
654 err.getvalue())
655
656 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
657 def testStatusReadPatch(self):
658 """Test handling a single patch in Patchwork"""
659 series = Series()
660 series.commits = [Commit('abcd')]
661
Simon Glassf9b03cf2020-11-03 13:54:14 -0700662 patches = status.collect_patches(series, 1234, None,
663 self._fake_patchwork)
Simon Glass3db916d2020-10-29 21:46:35 -0600664 self.assertEqual(1, len(patches))
665 patch = patches[0]
666 self.assertEqual('1', patch.id)
667 self.assertEqual('Some patch', patch.raw_subject)
668
669 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
670 def testParseSubject(self):
671 """Test parsing of the patch subject"""
672 patch = status.Patch('1')
673
674 # Simple patch not in a series
675 patch.parse_subject('Testing')
676 self.assertEqual('Testing', patch.raw_subject)
677 self.assertEqual('Testing', patch.subject)
678 self.assertEqual(1, patch.seq)
679 self.assertEqual(1, patch.count)
680 self.assertEqual(None, patch.prefix)
681 self.assertEqual(None, patch.version)
682
683 # First patch in a series
684 patch.parse_subject('[1/2] Testing')
685 self.assertEqual('[1/2] Testing', patch.raw_subject)
686 self.assertEqual('Testing', patch.subject)
687 self.assertEqual(1, patch.seq)
688 self.assertEqual(2, patch.count)
689 self.assertEqual(None, patch.prefix)
690 self.assertEqual(None, patch.version)
691
692 # Second patch in a series
693 patch.parse_subject('[2/2] Testing')
694 self.assertEqual('Testing', patch.subject)
695 self.assertEqual(2, patch.seq)
696 self.assertEqual(2, patch.count)
697 self.assertEqual(None, patch.prefix)
698 self.assertEqual(None, patch.version)
699
700 # RFC patch
701 patch.parse_subject('[RFC,3/7] Testing')
702 self.assertEqual('Testing', patch.subject)
703 self.assertEqual(3, patch.seq)
704 self.assertEqual(7, patch.count)
705 self.assertEqual('RFC', patch.prefix)
706 self.assertEqual(None, patch.version)
707
708 # Version patch
709 patch.parse_subject('[v2,3/7] Testing')
710 self.assertEqual('Testing', patch.subject)
711 self.assertEqual(3, patch.seq)
712 self.assertEqual(7, patch.count)
713 self.assertEqual(None, patch.prefix)
714 self.assertEqual('v2', patch.version)
715
716 # All fields
717 patch.parse_subject('[RESEND,v2,3/7] Testing')
718 self.assertEqual('Testing', patch.subject)
719 self.assertEqual(3, patch.seq)
720 self.assertEqual(7, patch.count)
721 self.assertEqual('RESEND', patch.prefix)
722 self.assertEqual('v2', patch.version)
723
724 # RFC only
725 patch.parse_subject('[RESEND] Testing')
726 self.assertEqual('Testing', patch.subject)
727 self.assertEqual(1, patch.seq)
728 self.assertEqual(1, patch.count)
729 self.assertEqual('RESEND', patch.prefix)
730 self.assertEqual(None, patch.version)
731
732 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
733 def testCompareSeries(self):
734 """Test operation of compare_with_series()"""
735 commit1 = Commit('abcd')
736 commit1.subject = 'Subject 1'
737 commit2 = Commit('ef12')
738 commit2.subject = 'Subject 2'
739 commit3 = Commit('3456')
740 commit3.subject = 'Subject 2'
741
742 patch1 = status.Patch('1')
743 patch1.subject = 'Subject 1'
744 patch2 = status.Patch('2')
745 patch2.subject = 'Subject 2'
746 patch3 = status.Patch('3')
747 patch3.subject = 'Subject 2'
748
749 series = Series()
750 series.commits = [commit1]
751 patches = [patch1]
752 patch_for_commit, commit_for_patch, warnings = (
753 status.compare_with_series(series, patches))
754 self.assertEqual(1, len(patch_for_commit))
755 self.assertEqual(patch1, patch_for_commit[0])
756 self.assertEqual(1, len(commit_for_patch))
757 self.assertEqual(commit1, commit_for_patch[0])
758
759 series.commits = [commit1]
760 patches = [patch1, patch2]
761 patch_for_commit, commit_for_patch, warnings = (
762 status.compare_with_series(series, patches))
763 self.assertEqual(1, len(patch_for_commit))
764 self.assertEqual(patch1, patch_for_commit[0])
765 self.assertEqual(1, len(commit_for_patch))
766 self.assertEqual(commit1, commit_for_patch[0])
767 self.assertEqual(["Cannot find commit for patch 2 ('Subject 2')"],
768 warnings)
769
770 series.commits = [commit1, commit2]
771 patches = [patch1]
772 patch_for_commit, commit_for_patch, warnings = (
773 status.compare_with_series(series, patches))
774 self.assertEqual(1, len(patch_for_commit))
775 self.assertEqual(patch1, patch_for_commit[0])
776 self.assertEqual(1, len(commit_for_patch))
777 self.assertEqual(commit1, commit_for_patch[0])
778 self.assertEqual(["Cannot find patch for commit 2 ('Subject 2')"],
779 warnings)
780
781 series.commits = [commit1, commit2, commit3]
782 patches = [patch1, patch2]
783 patch_for_commit, commit_for_patch, warnings = (
784 status.compare_with_series(series, patches))
785 self.assertEqual(2, len(patch_for_commit))
786 self.assertEqual(patch1, patch_for_commit[0])
787 self.assertEqual(patch2, patch_for_commit[1])
788 self.assertEqual(1, len(commit_for_patch))
789 self.assertEqual(commit1, commit_for_patch[0])
790 self.assertEqual(["Cannot find patch for commit 3 ('Subject 2')",
791 "Multiple commits match patch 2 ('Subject 2'):\n"
792 ' Subject 2\n Subject 2'],
793 warnings)
794
795 series.commits = [commit1, commit2]
796 patches = [patch1, patch2, patch3]
797 patch_for_commit, commit_for_patch, warnings = (
798 status.compare_with_series(series, patches))
799 self.assertEqual(1, len(patch_for_commit))
800 self.assertEqual(patch1, patch_for_commit[0])
801 self.assertEqual(2, len(commit_for_patch))
802 self.assertEqual(commit1, commit_for_patch[0])
803 self.assertEqual(["Multiple patches match commit 2 ('Subject 2'):\n"
804 ' Subject 2\n Subject 2',
805 "Cannot find commit for patch 3 ('Subject 2')"],
806 warnings)
807
Simon Glassf9b03cf2020-11-03 13:54:14 -0700808 def _fake_patchwork2(self, url, subpath):
Simon Glass3db916d2020-10-29 21:46:35 -0600809 """Fake Patchwork server for the function below
810
811 This handles accessing series, patches and comments, providing the data
812 in self.patches to the caller
Simon Glassf9b03cf2020-11-03 13:54:14 -0700813
814 Args:
815 url (str): URL of patchwork server
816 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600817 """
818 re_series = re.match(r'series/(\d*)/$', subpath)
819 re_patch = re.match(r'patches/(\d*)/$', subpath)
820 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
821 if re_series:
822 series_num = re_series.group(1)
823 if series_num == '1234':
824 return {'patches': self.patches}
825 elif re_patch:
826 patch_num = int(re_patch.group(1))
827 patch = self.patches[patch_num - 1]
828 return patch
829 elif re_comments:
830 patch_num = int(re_comments.group(1))
831 patch = self.patches[patch_num - 1]
832 return patch.comments
833 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
834
835 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
836 def testFindNewResponses(self):
837 """Test operation of find_new_responses()"""
838 commit1 = Commit('abcd')
839 commit1.subject = 'Subject 1'
840 commit2 = Commit('ef12')
841 commit2.subject = 'Subject 2'
842
843 patch1 = status.Patch('1')
844 patch1.parse_subject('[1/2] Subject 1')
845 patch1.name = patch1.raw_subject
846 patch1.content = 'This is my patch content'
847 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
848
849 patch1.comments = [comment1a]
850
851 patch2 = status.Patch('2')
852 patch2.parse_subject('[2/2] Subject 2')
853 patch2.name = patch2.raw_subject
854 patch2.content = 'Some other patch content'
855 comment2a = {
856 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
857 (self.mary, self.leb)}
858 comment2b = {'content': 'Reviewed-by: %s' % self.fred}
859 patch2.comments = [comment2a, comment2b]
860
861 # This test works by setting up commits and patch for use by the fake
862 # Rest API function _fake_patchwork2(). It calls various functions in
863 # the status module after setting up tags in the commits, checking that
864 # things behaves as expected
865 self.commits = [commit1, commit2]
866 self.patches = [patch1, patch2]
867 count = 2
868 new_rtag_list = [None] * count
Simon Glass2112d072020-10-29 21:46:38 -0600869 review_list = [None, None]
Simon Glass3db916d2020-10-29 21:46:35 -0600870
871 # Check that the tags are picked up on the first patch
Simon Glass2112d072020-10-29 21:46:38 -0600872 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700873 patch1, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600874 self.assertEqual(new_rtag_list[0], {'Reviewed-by': {self.joe}})
875
876 # Now the second patch
Simon Glass2112d072020-10-29 21:46:38 -0600877 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700878 patch2, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600879 self.assertEqual(new_rtag_list[1], {
880 'Reviewed-by': {self.mary, self.fred},
881 'Tested-by': {self.leb}})
882
883 # Now add some tags to the commit, which means they should not appear as
884 # 'new' tags when scanning comments
885 new_rtag_list = [None] * count
886 commit1.rtags = {'Reviewed-by': {self.joe}}
Simon Glass2112d072020-10-29 21:46:38 -0600887 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700888 patch1, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600889 self.assertEqual(new_rtag_list[0], {})
890
891 # For the second commit, add Ed and Fred, so only Mary should be left
892 commit2.rtags = {
893 'Tested-by': {self.leb},
894 'Reviewed-by': {self.fred}}
Simon Glass2112d072020-10-29 21:46:38 -0600895 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700896 patch2, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600897 self.assertEqual(new_rtag_list[1], {'Reviewed-by': {self.mary}})
898
899 # Check that the output patches expectations:
900 # 1 Subject 1
901 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
902 # 2 Subject 2
903 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
904 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
905 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
906 # 1 new response available in patchwork
907
908 series = Series()
909 series.commits = [commit1, commit2]
910 terminal.SetPrintTestMode()
Simon Glass2112d072020-10-29 21:46:38 -0600911 status.check_patchwork_status(series, '1234', None, None, False, False,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700912 None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600913 lines = iter(terminal.GetPrintTestLines())
914 col = terminal.Color()
915 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
916 next(lines))
917 self.assertEqual(
918 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
919 bright=False),
920 next(lines))
921 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE, bright=False),
922 next(lines))
923
924 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
925 next(lines))
926 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -0600927 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -0600928 bright=False),
929 next(lines))
Simon Glass2112d072020-10-29 21:46:38 -0600930 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE, bright=False),
Simon Glass3db916d2020-10-29 21:46:35 -0600931 next(lines))
932 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -0600933 terminal.PrintLine(' Tested-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -0600934 bright=False),
935 next(lines))
Simon Glass2112d072020-10-29 21:46:38 -0600936 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE, bright=False),
Simon Glass3db916d2020-10-29 21:46:35 -0600937 next(lines))
938 self.assertEqual(
939 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
940 next(lines))
941 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
942 next(lines))
943 self.assertEqual(terminal.PrintLine(
Simon Glassd0a0a582020-10-29 21:46:36 -0600944 '1 new response available in patchwork (use -d to write them to a new branch)',
945 None), next(lines))
946
Simon Glassf9b03cf2020-11-03 13:54:14 -0700947 def _fake_patchwork3(self, url, subpath):
Simon Glassd0a0a582020-10-29 21:46:36 -0600948 """Fake Patchwork server for the function below
949
950 This handles accessing series, patches and comments, providing the data
951 in self.patches to the caller
Simon Glassf9b03cf2020-11-03 13:54:14 -0700952
953 Args:
954 url (str): URL of patchwork server
955 subpath (str): URL subpath to use
Simon Glassd0a0a582020-10-29 21:46:36 -0600956 """
957 re_series = re.match(r'series/(\d*)/$', subpath)
958 re_patch = re.match(r'patches/(\d*)/$', subpath)
959 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
960 if re_series:
961 series_num = re_series.group(1)
962 if series_num == '1234':
963 return {'patches': self.patches}
964 elif re_patch:
965 patch_num = int(re_patch.group(1))
966 patch = self.patches[patch_num - 1]
967 return patch
968 elif re_comments:
969 patch_num = int(re_comments.group(1))
970 patch = self.patches[patch_num - 1]
971 return patch.comments
972 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
973
974 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
975 def testCreateBranch(self):
976 """Test operation of create_branch()"""
977 repo = self.make_git_tree()
978 branch = 'first'
979 dest_branch = 'first2'
980 count = 2
981 gitdir = os.path.join(self.gitdir, '.git')
982
983 # Set up the test git tree. We use branch 'first' which has two commits
984 # in it
985 series = patchstream.get_metadata_for_list(branch, gitdir, count)
986 self.assertEqual(2, len(series.commits))
987
988 patch1 = status.Patch('1')
989 patch1.parse_subject('[1/2] %s' % series.commits[0].subject)
990 patch1.name = patch1.raw_subject
991 patch1.content = 'This is my patch content'
992 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
993
994 patch1.comments = [comment1a]
995
996 patch2 = status.Patch('2')
997 patch2.parse_subject('[2/2] %s' % series.commits[1].subject)
998 patch2.name = patch2.raw_subject
999 patch2.content = 'Some other patch content'
1000 comment2a = {
1001 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1002 (self.mary, self.leb)}
1003 comment2b = {
1004 'content': 'Reviewed-by: %s' % self.fred}
1005 patch2.comments = [comment2a, comment2b]
1006
1007 # This test works by setting up patches for use by the fake Rest API
1008 # function _fake_patchwork3(). The fake patch comments above should
1009 # result in new review tags that are collected and added to the commits
1010 # created in the destination branch.
1011 self.patches = [patch1, patch2]
1012 count = 2
1013
1014 # Expected output:
1015 # 1 i2c: I2C things
1016 # + Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1017 # 2 spi: SPI fixes
1018 # + Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1019 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1020 # + Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1021 # 4 new responses available in patchwork
1022 # 4 responses added from patchwork into new branch 'first2'
1023 # <unittest.result.TestResult run=8 errors=0 failures=0>
1024
1025 terminal.SetPrintTestMode()
1026 status.check_patchwork_status(series, '1234', branch, dest_branch,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001027 False, False, None, self._fake_patchwork3,
1028 repo)
Simon Glassd0a0a582020-10-29 21:46:36 -06001029 lines = terminal.GetPrintTestLines()
1030 self.assertEqual(12, len(lines))
1031 self.assertEqual(
1032 "4 responses added from patchwork into new branch 'first2'",
1033 lines[11].text)
1034
1035 # Check that the destination branch has the new tags
1036 new_series = patchstream.get_metadata_for_list(dest_branch, gitdir,
1037 count)
1038 self.assertEqual(
1039 {'Reviewed-by': {self.joe}},
1040 new_series.commits[0].rtags)
1041 self.assertEqual(
1042 {'Tested-by': {self.leb},
1043 'Reviewed-by': {self.fred, self.mary}},
1044 new_series.commits[1].rtags)
1045
1046 # Now check the actual test of the first commit message. We expect to
1047 # see the new tags immediately below the old ones.
1048 stdout = patchstream.get_list(dest_branch, count=count, git_dir=gitdir)
1049 lines = iter([line.strip() for line in stdout.splitlines()
1050 if '-by:' in line])
1051
1052 # First patch should have the review tag
1053 self.assertEqual('Reviewed-by: %s' % self.joe, next(lines))
1054
1055 # Second patch should have the sign-off then the tested-by and two
1056 # reviewed-by tags
1057 self.assertEqual('Signed-off-by: %s' % self.leb, next(lines))
1058 self.assertEqual('Reviewed-by: %s' % self.fred, next(lines))
1059 self.assertEqual('Reviewed-by: %s' % self.mary, next(lines))
1060 self.assertEqual('Tested-by: %s' % self.leb, next(lines))
Simon Glassda8a2922020-10-29 21:46:37 -06001061
Simon Glass2112d072020-10-29 21:46:38 -06001062 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
Simon Glassda8a2922020-10-29 21:46:37 -06001063 def testParseSnippets(self):
1064 """Test parsing of review snippets"""
1065 text = '''Hi Fred,
1066
1067This is a comment from someone.
1068
1069Something else
1070
1071On some recent date, Fred wrote:
1072> This is why I wrote the patch
1073> so here it is
1074
1075Now a comment about the commit message
1076A little more to say
1077
1078Even more
1079
1080> diff --git a/file.c b/file.c
1081> Some more code
1082> Code line 2
1083> Code line 3
1084> Code line 4
1085> Code line 5
1086> Code line 6
1087> Code line 7
1088> Code line 8
1089> Code line 9
1090
1091And another comment
1092
1093> @@ -153,8 +143,13 @@ def CheckPatch(fname, show_types=False):
1094> further down on the file
1095> and more code
1096> +Addition here
1097> +Another addition here
1098> codey
1099> more codey
1100
1101and another thing in same file
1102
1103> @@ -253,8 +243,13 @@
1104> with no function context
1105
1106one more thing
1107
1108> diff --git a/tools/patman/main.py b/tools/patman/main.py
1109> +line of code
1110now a very long comment in a different file
1111line2
1112line3
1113line4
1114line5
1115line6
1116line7
1117line8
1118'''
1119 pstrm = PatchStream.process_text(text, True)
1120 self.assertEqual([], pstrm.commit.warn)
1121
1122 # We expect to the filename and up to 5 lines of code context before
1123 # each comment. The 'On xxx wrote:' bit should be removed.
1124 self.assertEqual(
1125 [['Hi Fred,',
1126 'This is a comment from someone.',
1127 'Something else'],
1128 ['> This is why I wrote the patch',
1129 '> so here it is',
1130 'Now a comment about the commit message',
1131 'A little more to say', 'Even more'],
1132 ['> File: file.c', '> Code line 5', '> Code line 6',
1133 '> Code line 7', '> Code line 8', '> Code line 9',
1134 'And another comment'],
1135 ['> File: file.c',
1136 '> Line: 153 / 143: def CheckPatch(fname, show_types=False):',
1137 '> and more code', '> +Addition here', '> +Another addition here',
1138 '> codey', '> more codey', 'and another thing in same file'],
1139 ['> File: file.c', '> Line: 253 / 243',
1140 '> with no function context', 'one more thing'],
1141 ['> File: tools/patman/main.py', '> +line of code',
1142 'now a very long comment in a different file',
1143 'line2', 'line3', 'line4', 'line5', 'line6', 'line7', 'line8']],
1144 pstrm.snippets)
Simon Glass2112d072020-10-29 21:46:38 -06001145
1146 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
1147 def testReviewSnippets(self):
1148 """Test showing of review snippets"""
1149 def _to_submitter(who):
1150 m_who = re.match('(.*) <(.*)>', who)
1151 return {
1152 'name': m_who.group(1),
1153 'email': m_who.group(2)
1154 }
1155
1156 commit1 = Commit('abcd')
1157 commit1.subject = 'Subject 1'
1158 commit2 = Commit('ef12')
1159 commit2.subject = 'Subject 2'
1160
1161 patch1 = status.Patch('1')
1162 patch1.parse_subject('[1/2] Subject 1')
1163 patch1.name = patch1.raw_subject
1164 patch1.content = 'This is my patch content'
1165 comment1a = {'submitter': _to_submitter(self.joe),
1166 'content': '''Hi Fred,
1167
1168On some date Fred wrote:
1169
1170> diff --git a/file.c b/file.c
1171> Some code
1172> and more code
1173
1174Here is my comment above the above...
1175
1176
1177Reviewed-by: %s
1178''' % self.joe}
1179
1180 patch1.comments = [comment1a]
1181
1182 patch2 = status.Patch('2')
1183 patch2.parse_subject('[2/2] Subject 2')
1184 patch2.name = patch2.raw_subject
1185 patch2.content = 'Some other patch content'
1186 comment2a = {
1187 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1188 (self.mary, self.leb)}
1189 comment2b = {'submitter': _to_submitter(self.fred),
1190 'content': '''Hi Fred,
1191
1192On some date Fred wrote:
1193
1194> diff --git a/tools/patman/commit.py b/tools/patman/commit.py
1195> @@ -41,6 +41,9 @@ class Commit:
1196> self.rtags = collections.defaultdict(set)
1197> self.warn = []
1198>
1199> + def __str__(self):
1200> + return self.subject
1201> +
1202> def AddChange(self, version, info):
1203> """Add a new change line to the change list for a version.
1204>
1205A comment
1206
1207Reviewed-by: %s
1208''' % self.fred}
1209 patch2.comments = [comment2a, comment2b]
1210
1211 # This test works by setting up commits and patch for use by the fake
1212 # Rest API function _fake_patchwork2(). It calls various functions in
1213 # the status module after setting up tags in the commits, checking that
1214 # things behaves as expected
1215 self.commits = [commit1, commit2]
1216 self.patches = [patch1, patch2]
1217
1218 # Check that the output patches expectations:
1219 # 1 Subject 1
1220 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1221 # 2 Subject 2
1222 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1223 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1224 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1225 # 1 new response available in patchwork
1226
1227 series = Series()
1228 series.commits = [commit1, commit2]
1229 terminal.SetPrintTestMode()
1230 status.check_patchwork_status(series, '1234', None, None, False, True,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001231 None, self._fake_patchwork2)
Simon Glass2112d072020-10-29 21:46:38 -06001232 lines = iter(terminal.GetPrintTestLines())
1233 col = terminal.Color()
1234 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
1235 next(lines))
1236 self.assertEqual(
1237 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1238 next(lines))
1239 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE), next(lines))
1240
1241 self.assertEqual(terminal.PrintLine('Review: %s' % self.joe, col.RED),
1242 next(lines))
1243 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1244 self.assertEqual(terminal.PrintLine('', None), next(lines))
1245 self.assertEqual(terminal.PrintLine(' > File: file.c', col.MAGENTA),
1246 next(lines))
1247 self.assertEqual(terminal.PrintLine(' > Some code', col.MAGENTA),
1248 next(lines))
1249 self.assertEqual(terminal.PrintLine(' > and more code', col.MAGENTA),
1250 next(lines))
1251 self.assertEqual(terminal.PrintLine(
1252 ' Here is my comment above the above...', None), next(lines))
1253 self.assertEqual(terminal.PrintLine('', None), next(lines))
1254
1255 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
1256 next(lines))
1257 self.assertEqual(
1258 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1259 next(lines))
1260 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE),
1261 next(lines))
1262 self.assertEqual(
1263 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1264 next(lines))
1265 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
1266 next(lines))
1267 self.assertEqual(
1268 terminal.PrintLine(' + Tested-by: ', col.GREEN, newline=False),
1269 next(lines))
1270 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE),
1271 next(lines))
1272
1273 self.assertEqual(terminal.PrintLine('Review: %s' % self.fred, col.RED),
1274 next(lines))
1275 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1276 self.assertEqual(terminal.PrintLine('', None), next(lines))
1277 self.assertEqual(terminal.PrintLine(
1278 ' > File: tools/patman/commit.py', col.MAGENTA), next(lines))
1279 self.assertEqual(terminal.PrintLine(
1280 ' > Line: 41 / 41: class Commit:', col.MAGENTA), next(lines))
1281 self.assertEqual(terminal.PrintLine(
1282 ' > + return self.subject', col.MAGENTA), next(lines))
1283 self.assertEqual(terminal.PrintLine(
1284 ' > +', col.MAGENTA), next(lines))
1285 self.assertEqual(
1286 terminal.PrintLine(' > def AddChange(self, version, info):',
1287 col.MAGENTA),
1288 next(lines))
1289 self.assertEqual(terminal.PrintLine(
1290 ' > """Add a new change line to the change list for a version.',
1291 col.MAGENTA), next(lines))
1292 self.assertEqual(terminal.PrintLine(
1293 ' >', col.MAGENTA), next(lines))
1294 self.assertEqual(terminal.PrintLine(
1295 ' A comment', None), next(lines))
1296 self.assertEqual(terminal.PrintLine('', None), next(lines))
1297
1298 self.assertEqual(terminal.PrintLine(
1299 '4 new responses available in patchwork (use -d to write them to a new branch)',
1300 None), next(lines))