blob: 450fe6659c4cce5642165122784cfa5bf1253466 [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
Simon Glass1f975b92021-01-23 08:56:15 -0700189 ignore_bad_tags = False
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)
Simon Glass9dfb3112020-11-08 20:36:18 -0700240 self.assertEqual('Cc: %s' % stefan, next(lines))
Simon Glass42e3d392020-10-29 21:46:29 -0600241 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 Glass9dfb3112020-11-08 20:36:18 -0700245 self.assertEqual(' Cc: %s' % self.leb,
Simon Glass42e3d392020-10-29 21:46:29 -0600246 next(lines))
Simon Glass9dfb3112020-11-08 20:36:18 -0700247 self.assertEqual(' Cc: %s' % mel, next(lines))
Simon Glass42e3d392020-10-29 21:46:29 -0600248 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 Glass9dfb3112020-11-08 20:36:18 -0700254 self.assertEqual(expected, next(lines))
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600255
Simon Glass9dfb3112020-11-08 20:36:18 -0700256 self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)), cc_lines[0])
Simon Glass95745aa2020-10-29 21:46:13 -0600257 self.assertEqual(
Simon Glass3b762cc2020-10-29 21:46:28 -0600258 '%s %s\0%s\0%s\0%s' % (args[1], self.fred, self.leb, rick, stefan),
Simon Glass9dfb3112020-11-08 20:36:18 -0700259 cc_lines[1])
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600260
261 expected = '''
262This is a test of how the cover
Sean Andersoncf13b862020-05-04 16:28:36 -0400263letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600264works
265
266some notes
267about some things
268from the first commit
269
270Changes in v4:
Sean Andersoncf13b862020-05-04 16:28:36 -0400271- Multi
272 line
273 change
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600274- Some changes
Sean Andersoncf13b862020-05-04 16:28:36 -0400275- Some notes for the cover letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600276
277Simon Glass (2):
278 pci: Correct cast for sandbox
Siva Durga Prasad Paladugub3d55ea2018-07-16 15:56:11 +0530279 fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600280
281 cmd/pci.c | 3 ++-
282 fs/fat/fat.c | 1 +
283 lib/efi_loader/efi_memory.c | 1 +
284 lib/fdtdec.c | 3 ++-
285 4 files changed, 6 insertions(+), 2 deletions(-)
286
287--\x20
2882.7.4
289
290'''
Simon Glassf544a2d2019-10-31 07:42:51 -0600291 lines = open(cover_fname, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600292 self.assertEqual(
Simon Glass95745aa2020-10-29 21:46:13 -0600293 'Subject: [RFC PATCH v3 0/2] test: A test patch series',
294 lines[3])
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600295 self.assertEqual(expected.splitlines(), lines[7:])
296
297 for i, fname in enumerate(args):
Simon Glassf544a2d2019-10-31 07:42:51 -0600298 lines = open(fname, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600299 subject = [line for line in lines if line.startswith('Subject')]
300 self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count),
301 subject[0][:18])
Sean Andersoncf13b862020-05-04 16:28:36 -0400302
303 # Check that we got our commit notes
304 start = 0
305 expected = ''
306
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600307 if i == 0:
Sean Andersoncf13b862020-05-04 16:28:36 -0400308 start = 17
309 expected = '''---
310Some notes about
311the first commit
312
313(no changes since v2)
314
315Changes in v2:
316- second revision change'''
317 elif i == 1:
318 start = 17
319 expected = '''---
320
321Changes in v4:
322- Multi
323 line
324 change
325- Some changes
326
327Changes in v2:
328- Changes only for this commit'''
329
330 if expected:
331 expected = expected.splitlines()
332 self.assertEqual(expected, lines[start:(start+len(expected))])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600333
334 def make_commit_with_file(self, subject, body, fname, text):
335 """Create a file and add it to the git repo with a new commit
336
337 Args:
338 subject (str): Subject for the commit
339 body (str): Body text of the commit
340 fname (str): Filename of file to create
341 text (str): Text to put into the file
342 """
343 path = os.path.join(self.gitdir, fname)
344 tools.WriteFile(path, text, binary=False)
345 index = self.repo.index
346 index.add(fname)
Simon Glass95745aa2020-10-29 21:46:13 -0600347 author = pygit2.Signature('Test user', 'test@email.com')
Simon Glass54f1c5b2020-07-05 21:41:50 -0600348 committer = author
349 tree = index.write_tree()
350 message = subject + '\n' + body
351 self.repo.create_commit('HEAD', author, committer, message, tree,
352 [self.repo.head.target])
353
354 def make_git_tree(self):
355 """Make a simple git tree suitable for testing
356
357 It has three branches:
358 'base' has two commits: PCI, main
359 'first' has base as upstream and two more commits: I2C, SPI
360 'second' has base as upstream and three more: video, serial, bootm
361
362 Returns:
Simon Glasseb209e52020-10-29 21:46:15 -0600363 pygit2.Repository: repository
Simon Glass54f1c5b2020-07-05 21:41:50 -0600364 """
365 repo = pygit2.init_repository(self.gitdir)
366 self.repo = repo
367 new_tree = repo.TreeBuilder().write()
368
369 author = pygit2.Signature('Test user', 'test@email.com')
370 committer = author
Simon Glasseb209e52020-10-29 21:46:15 -0600371 _ = repo.create_commit('HEAD', author, committer, 'Created master',
372 new_tree, [])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600373
374 self.make_commit_with_file('Initial commit', '''
375Add a README
376
377''', 'README', '''This is the README file
378describing this project
379in very little detail''')
380
381 self.make_commit_with_file('pci: PCI implementation', '''
382Here is a basic PCI implementation
383
384''', 'pci.c', '''This is a file
385it has some contents
386and some more things''')
387 self.make_commit_with_file('main: Main program', '''
388Hello here is the second commit.
389''', 'main.c', '''This is the main file
390there is very little here
391but we can always add more later
392if we want to
393
394Series-to: u-boot
395Series-cc: Barry Crump <bcrump@whataroa.nz>
396''')
397 base_target = repo.revparse_single('HEAD')
398 self.make_commit_with_file('i2c: I2C things', '''
399This has some stuff to do with I2C
400''', 'i2c.c', '''And this is the file contents
401with some I2C-related things in it''')
402 self.make_commit_with_file('spi: SPI fixes', '''
403SPI needs some fixes
404and here they are
Simon Glassd0a0a582020-10-29 21:46:36 -0600405
406Signed-off-by: %s
407
408Series-to: u-boot
409Commit-notes:
410title of the series
411This is the cover letter for the series
412with various details
413END
414''' % self.leb, 'spi.c', '''Some fixes for SPI in this
Simon Glass54f1c5b2020-07-05 21:41:50 -0600415file to make SPI work
416better than before''')
417 first_target = repo.revparse_single('HEAD')
418
419 target = repo.revparse_single('HEAD~2')
420 repo.reset(target.oid, pygit2.GIT_CHECKOUT_FORCE)
421 self.make_commit_with_file('video: Some video improvements', '''
422Fix up the video so that
423it looks more purple. Purple is
424a very nice colour.
425''', 'video.c', '''More purple here
426Purple and purple
427Even more purple
428Could not be any more purple''')
429 self.make_commit_with_file('serial: Add a serial driver', '''
430Here is the serial driver
431for my chip.
432
433Cover-letter:
434Series for my board
435This series implements support
436for my glorious board.
437END
Simon Glassa80986c2020-10-29 21:46:16 -0600438Series-links: 183237
Simon Glass54f1c5b2020-07-05 21:41:50 -0600439''', 'serial.c', '''The code for the
440serial driver is here''')
441 self.make_commit_with_file('bootm: Make it boot', '''
442This makes my board boot
443with a fix to the bootm
444command
445''', 'bootm.c', '''Fix up the bootm
446command to make the code as
447complicated as possible''')
448 second_target = repo.revparse_single('HEAD')
449
450 repo.branches.local.create('first', first_target)
451 repo.config.set_multivar('branch.first.remote', '', '.')
452 repo.config.set_multivar('branch.first.merge', '', 'refs/heads/base')
453
454 repo.branches.local.create('second', second_target)
455 repo.config.set_multivar('branch.second.remote', '', '.')
456 repo.config.set_multivar('branch.second.merge', '', 'refs/heads/base')
457
458 repo.branches.local.create('base', base_target)
459 return repo
460
461 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
462 def testBranch(self):
463 """Test creating patches from a branch"""
464 repo = self.make_git_tree()
465 target = repo.lookup_reference('refs/heads/first')
466 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
467 control.setup()
468 try:
469 orig_dir = os.getcwd()
470 os.chdir(self.gitdir)
471
472 # Check that it can detect the current branch
Simon Glass2eb4da72020-07-05 21:41:51 -0600473 self.assertEqual(2, gitutil.CountCommitsToBranch(None))
Simon Glass54f1c5b2020-07-05 21:41:50 -0600474 col = terminal.Color()
475 with capture_sys_output() as _:
476 _, cover_fname, patch_files = control.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600477 col, branch=None, count=-1, start=0, end=0,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100478 ignore_binary=False, signoff=True)
Simon Glass54f1c5b2020-07-05 21:41:50 -0600479 self.assertIsNone(cover_fname)
480 self.assertEqual(2, len(patch_files))
Simon Glass2eb4da72020-07-05 21:41:51 -0600481
482 # Check that it can detect a different branch
483 self.assertEqual(3, gitutil.CountCommitsToBranch('second'))
484 with capture_sys_output() as _:
485 _, cover_fname, patch_files = control.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600486 col, branch='second', count=-1, start=0, end=0,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100487 ignore_binary=False, signoff=True)
Simon Glass2eb4da72020-07-05 21:41:51 -0600488 self.assertIsNotNone(cover_fname)
489 self.assertEqual(3, len(patch_files))
Simon Glassb3bf4e12020-07-05 21:41:52 -0600490
491 # Check that it can skip patches at the end
492 with capture_sys_output() as _:
493 _, cover_fname, patch_files = control.prepare_patches(
494 col, branch='second', count=-1, start=0, end=1,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100495 ignore_binary=False, signoff=True)
Simon Glassb3bf4e12020-07-05 21:41:52 -0600496 self.assertIsNotNone(cover_fname)
497 self.assertEqual(2, len(patch_files))
Simon Glass54f1c5b2020-07-05 21:41:50 -0600498 finally:
499 os.chdir(orig_dir)
Simon Glass06202d62020-10-29 21:46:27 -0600500
501 def testTags(self):
502 """Test collection of tags in a patchstream"""
503 text = '''This is a patch
504
505Signed-off-by: Terminator
Simon Glass3b762cc2020-10-29 21:46:28 -0600506Reviewed-by: %s
507Reviewed-by: %s
Simon Glass06202d62020-10-29 21:46:27 -0600508Tested-by: %s
Simon Glass3b762cc2020-10-29 21:46:28 -0600509''' % (self.joe, self.mary, self.leb)
Simon Glass06202d62020-10-29 21:46:27 -0600510 pstrm = PatchStream.process_text(text)
511 self.assertEqual(pstrm.commit.rtags, {
Simon Glass3b762cc2020-10-29 21:46:28 -0600512 'Reviewed-by': {self.joe, self.mary},
Simon Glass06202d62020-10-29 21:46:27 -0600513 'Tested-by': {self.leb}})
Simon Glass3b762cc2020-10-29 21:46:28 -0600514
515 def testMissingEnd(self):
516 """Test a missing END tag"""
517 text = '''This is a patch
518
519Cover-letter:
520This is the title
521missing END after this line
522Signed-off-by: Fred
523'''
524 pstrm = PatchStream.process_text(text)
525 self.assertEqual(["Missing 'END' in section 'cover'"],
526 pstrm.commit.warn)
527
528 def testMissingBlankLine(self):
529 """Test a missing blank line after a tag"""
530 text = '''This is a patch
531
532Series-changes: 2
533- First line of changes
534- Missing blank line after this line
535Signed-off-by: Fred
536'''
537 pstrm = PatchStream.process_text(text)
538 self.assertEqual(["Missing 'blank line' in section 'Series-changes'"],
539 pstrm.commit.warn)
540
541 def testInvalidCommitTag(self):
542 """Test an invalid Commit-xxx tag"""
543 text = '''This is a patch
544
545Commit-fred: testing
546'''
547 pstrm = PatchStream.process_text(text)
548 self.assertEqual(["Line 3: Ignoring Commit-fred"], pstrm.commit.warn)
549
550 def testSelfTest(self):
551 """Test a tested by tag by this user"""
552 test_line = 'Tested-by: %s@napier.com' % os.getenv('USER')
553 text = '''This is a patch
554
555%s
556''' % test_line
557 pstrm = PatchStream.process_text(text)
558 self.assertEqual(["Ignoring '%s'" % test_line], pstrm.commit.warn)
559
560 def testSpaceBeforeTab(self):
561 """Test a space before a tab"""
562 text = '''This is a patch
563
564+ \tSomething
565'''
566 pstrm = PatchStream.process_text(text)
567 self.assertEqual(["Line 3/0 has space before tab"], pstrm.commit.warn)
568
569 def testLinesAfterTest(self):
570 """Test detecting lines after TEST= line"""
571 text = '''This is a patch
572
573TEST=sometest
574more lines
575here
576'''
577 pstrm = PatchStream.process_text(text)
578 self.assertEqual(["Found 2 lines after TEST="], pstrm.commit.warn)
579
580 def testBlankLineAtEnd(self):
581 """Test detecting a blank line at the end of a file"""
582 text = '''This is a patch
583
584diff --git a/lib/fdtdec.c b/lib/fdtdec.c
585index c072e54..942244f 100644
586--- a/lib/fdtdec.c
587+++ b/lib/fdtdec.c
588@@ -1200,7 +1200,8 @@ int fdtdec_setup_mem_size_base(void)
589 }
590
591 gd->ram_size = (phys_size_t)(res.end - res.start + 1);
592- debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size);
593+ debug("%s: Initial DRAM size %llx\n", __func__,
594+ (unsigned long long)gd->ram_size);
595+
596diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
597
598--
5992.7.4
600
601 '''
602 pstrm = PatchStream.process_text(text)
603 self.assertEqual(
604 ["Found possible blank line(s) at end of file 'lib/fdtdec.c'"],
605 pstrm.commit.warn)
Simon Glass1c1f2072020-10-29 21:46:34 -0600606
607 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
608 def testNoUpstream(self):
609 """Test CountCommitsToBranch when there is no upstream"""
610 repo = self.make_git_tree()
611 target = repo.lookup_reference('refs/heads/base')
612 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
613
614 # Check that it can detect the current branch
615 try:
616 orig_dir = os.getcwd()
617 os.chdir(self.gitdir)
618 with self.assertRaises(ValueError) as exc:
619 gitutil.CountCommitsToBranch(None)
620 self.assertIn(
621 "Failed to determine upstream: fatal: no upstream configured for branch 'base'",
622 str(exc.exception))
623 finally:
624 os.chdir(orig_dir)
Simon Glass3db916d2020-10-29 21:46:35 -0600625
626 @staticmethod
Simon Glassf9b03cf2020-11-03 13:54:14 -0700627 def _fake_patchwork(url, subpath):
Simon Glass3db916d2020-10-29 21:46:35 -0600628 """Fake Patchwork server for the function below
629
630 This handles accessing a series, providing a list consisting of a
631 single patch
Simon Glassf9b03cf2020-11-03 13:54:14 -0700632
633 Args:
634 url (str): URL of patchwork server
635 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600636 """
637 re_series = re.match(r'series/(\d*)/$', subpath)
638 if re_series:
639 series_num = re_series.group(1)
640 if series_num == '1234':
641 return {'patches': [
642 {'id': '1', 'name': 'Some patch'}]}
643 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
644
645 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
646 def testStatusMismatch(self):
647 """Test Patchwork patches not matching the series"""
648 series = Series()
649
650 with capture_sys_output() as (_, err):
Simon Glassf9b03cf2020-11-03 13:54:14 -0700651 status.collect_patches(series, 1234, None, self._fake_patchwork)
Simon Glass3db916d2020-10-29 21:46:35 -0600652 self.assertIn('Warning: Patchwork reports 1 patches, series has 0',
653 err.getvalue())
654
655 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
656 def testStatusReadPatch(self):
657 """Test handling a single patch in Patchwork"""
658 series = Series()
659 series.commits = [Commit('abcd')]
660
Simon Glassf9b03cf2020-11-03 13:54:14 -0700661 patches = status.collect_patches(series, 1234, None,
662 self._fake_patchwork)
Simon Glass3db916d2020-10-29 21:46:35 -0600663 self.assertEqual(1, len(patches))
664 patch = patches[0]
665 self.assertEqual('1', patch.id)
666 self.assertEqual('Some patch', patch.raw_subject)
667
668 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
669 def testParseSubject(self):
670 """Test parsing of the patch subject"""
671 patch = status.Patch('1')
672
673 # Simple patch not in a series
674 patch.parse_subject('Testing')
675 self.assertEqual('Testing', patch.raw_subject)
676 self.assertEqual('Testing', patch.subject)
677 self.assertEqual(1, patch.seq)
678 self.assertEqual(1, patch.count)
679 self.assertEqual(None, patch.prefix)
680 self.assertEqual(None, patch.version)
681
682 # First patch in a series
683 patch.parse_subject('[1/2] Testing')
684 self.assertEqual('[1/2] Testing', patch.raw_subject)
685 self.assertEqual('Testing', patch.subject)
686 self.assertEqual(1, patch.seq)
687 self.assertEqual(2, patch.count)
688 self.assertEqual(None, patch.prefix)
689 self.assertEqual(None, patch.version)
690
691 # Second patch in a series
692 patch.parse_subject('[2/2] Testing')
693 self.assertEqual('Testing', patch.subject)
694 self.assertEqual(2, patch.seq)
695 self.assertEqual(2, patch.count)
696 self.assertEqual(None, patch.prefix)
697 self.assertEqual(None, patch.version)
698
699 # RFC patch
700 patch.parse_subject('[RFC,3/7] Testing')
701 self.assertEqual('Testing', patch.subject)
702 self.assertEqual(3, patch.seq)
703 self.assertEqual(7, patch.count)
704 self.assertEqual('RFC', patch.prefix)
705 self.assertEqual(None, patch.version)
706
707 # Version patch
708 patch.parse_subject('[v2,3/7] Testing')
709 self.assertEqual('Testing', patch.subject)
710 self.assertEqual(3, patch.seq)
711 self.assertEqual(7, patch.count)
712 self.assertEqual(None, patch.prefix)
713 self.assertEqual('v2', patch.version)
714
715 # All fields
716 patch.parse_subject('[RESEND,v2,3/7] Testing')
717 self.assertEqual('Testing', patch.subject)
718 self.assertEqual(3, patch.seq)
719 self.assertEqual(7, patch.count)
720 self.assertEqual('RESEND', patch.prefix)
721 self.assertEqual('v2', patch.version)
722
723 # RFC only
724 patch.parse_subject('[RESEND] Testing')
725 self.assertEqual('Testing', patch.subject)
726 self.assertEqual(1, patch.seq)
727 self.assertEqual(1, patch.count)
728 self.assertEqual('RESEND', patch.prefix)
729 self.assertEqual(None, patch.version)
730
731 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
732 def testCompareSeries(self):
733 """Test operation of compare_with_series()"""
734 commit1 = Commit('abcd')
735 commit1.subject = 'Subject 1'
736 commit2 = Commit('ef12')
737 commit2.subject = 'Subject 2'
738 commit3 = Commit('3456')
739 commit3.subject = 'Subject 2'
740
741 patch1 = status.Patch('1')
742 patch1.subject = 'Subject 1'
743 patch2 = status.Patch('2')
744 patch2.subject = 'Subject 2'
745 patch3 = status.Patch('3')
746 patch3.subject = 'Subject 2'
747
748 series = Series()
749 series.commits = [commit1]
750 patches = [patch1]
751 patch_for_commit, commit_for_patch, warnings = (
752 status.compare_with_series(series, patches))
753 self.assertEqual(1, len(patch_for_commit))
754 self.assertEqual(patch1, patch_for_commit[0])
755 self.assertEqual(1, len(commit_for_patch))
756 self.assertEqual(commit1, commit_for_patch[0])
757
758 series.commits = [commit1]
759 patches = [patch1, patch2]
760 patch_for_commit, commit_for_patch, warnings = (
761 status.compare_with_series(series, patches))
762 self.assertEqual(1, len(patch_for_commit))
763 self.assertEqual(patch1, patch_for_commit[0])
764 self.assertEqual(1, len(commit_for_patch))
765 self.assertEqual(commit1, commit_for_patch[0])
766 self.assertEqual(["Cannot find commit for patch 2 ('Subject 2')"],
767 warnings)
768
769 series.commits = [commit1, commit2]
770 patches = [patch1]
771 patch_for_commit, commit_for_patch, warnings = (
772 status.compare_with_series(series, patches))
773 self.assertEqual(1, len(patch_for_commit))
774 self.assertEqual(patch1, patch_for_commit[0])
775 self.assertEqual(1, len(commit_for_patch))
776 self.assertEqual(commit1, commit_for_patch[0])
777 self.assertEqual(["Cannot find patch for commit 2 ('Subject 2')"],
778 warnings)
779
780 series.commits = [commit1, commit2, commit3]
781 patches = [patch1, patch2]
782 patch_for_commit, commit_for_patch, warnings = (
783 status.compare_with_series(series, patches))
784 self.assertEqual(2, len(patch_for_commit))
785 self.assertEqual(patch1, patch_for_commit[0])
786 self.assertEqual(patch2, patch_for_commit[1])
787 self.assertEqual(1, len(commit_for_patch))
788 self.assertEqual(commit1, commit_for_patch[0])
789 self.assertEqual(["Cannot find patch for commit 3 ('Subject 2')",
790 "Multiple commits match patch 2 ('Subject 2'):\n"
791 ' Subject 2\n Subject 2'],
792 warnings)
793
794 series.commits = [commit1, commit2]
795 patches = [patch1, patch2, patch3]
796 patch_for_commit, commit_for_patch, warnings = (
797 status.compare_with_series(series, patches))
798 self.assertEqual(1, len(patch_for_commit))
799 self.assertEqual(patch1, patch_for_commit[0])
800 self.assertEqual(2, len(commit_for_patch))
801 self.assertEqual(commit1, commit_for_patch[0])
802 self.assertEqual(["Multiple patches match commit 2 ('Subject 2'):\n"
803 ' Subject 2\n Subject 2',
804 "Cannot find commit for patch 3 ('Subject 2')"],
805 warnings)
806
Simon Glassf9b03cf2020-11-03 13:54:14 -0700807 def _fake_patchwork2(self, url, subpath):
Simon Glass3db916d2020-10-29 21:46:35 -0600808 """Fake Patchwork server for the function below
809
810 This handles accessing series, patches and comments, providing the data
811 in self.patches to the caller
Simon Glassf9b03cf2020-11-03 13:54:14 -0700812
813 Args:
814 url (str): URL of patchwork server
815 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600816 """
817 re_series = re.match(r'series/(\d*)/$', subpath)
818 re_patch = re.match(r'patches/(\d*)/$', subpath)
819 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
820 if re_series:
821 series_num = re_series.group(1)
822 if series_num == '1234':
823 return {'patches': self.patches}
824 elif re_patch:
825 patch_num = int(re_patch.group(1))
826 patch = self.patches[patch_num - 1]
827 return patch
828 elif re_comments:
829 patch_num = int(re_comments.group(1))
830 patch = self.patches[patch_num - 1]
831 return patch.comments
832 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
833
834 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
835 def testFindNewResponses(self):
836 """Test operation of find_new_responses()"""
837 commit1 = Commit('abcd')
838 commit1.subject = 'Subject 1'
839 commit2 = Commit('ef12')
840 commit2.subject = 'Subject 2'
841
842 patch1 = status.Patch('1')
843 patch1.parse_subject('[1/2] Subject 1')
844 patch1.name = patch1.raw_subject
845 patch1.content = 'This is my patch content'
846 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
847
848 patch1.comments = [comment1a]
849
850 patch2 = status.Patch('2')
851 patch2.parse_subject('[2/2] Subject 2')
852 patch2.name = patch2.raw_subject
853 patch2.content = 'Some other patch content'
854 comment2a = {
855 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
856 (self.mary, self.leb)}
857 comment2b = {'content': 'Reviewed-by: %s' % self.fred}
858 patch2.comments = [comment2a, comment2b]
859
860 # This test works by setting up commits and patch for use by the fake
861 # Rest API function _fake_patchwork2(). It calls various functions in
862 # the status module after setting up tags in the commits, checking that
863 # things behaves as expected
864 self.commits = [commit1, commit2]
865 self.patches = [patch1, patch2]
866 count = 2
867 new_rtag_list = [None] * count
Simon Glass2112d072020-10-29 21:46:38 -0600868 review_list = [None, None]
Simon Glass3db916d2020-10-29 21:46:35 -0600869
870 # Check that the tags are picked up on the first patch
Simon Glass2112d072020-10-29 21:46:38 -0600871 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700872 patch1, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600873 self.assertEqual(new_rtag_list[0], {'Reviewed-by': {self.joe}})
874
875 # Now the second patch
Simon Glass2112d072020-10-29 21:46:38 -0600876 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700877 patch2, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600878 self.assertEqual(new_rtag_list[1], {
879 'Reviewed-by': {self.mary, self.fred},
880 'Tested-by': {self.leb}})
881
882 # Now add some tags to the commit, which means they should not appear as
883 # 'new' tags when scanning comments
884 new_rtag_list = [None] * count
885 commit1.rtags = {'Reviewed-by': {self.joe}}
Simon Glass2112d072020-10-29 21:46:38 -0600886 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700887 patch1, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600888 self.assertEqual(new_rtag_list[0], {})
889
890 # For the second commit, add Ed and Fred, so only Mary should be left
891 commit2.rtags = {
892 'Tested-by': {self.leb},
893 'Reviewed-by': {self.fred}}
Simon Glass2112d072020-10-29 21:46:38 -0600894 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700895 patch2, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600896 self.assertEqual(new_rtag_list[1], {'Reviewed-by': {self.mary}})
897
898 # Check that the output patches expectations:
899 # 1 Subject 1
900 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
901 # 2 Subject 2
902 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
903 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
904 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
905 # 1 new response available in patchwork
906
907 series = Series()
908 series.commits = [commit1, commit2]
909 terminal.SetPrintTestMode()
Simon Glass2112d072020-10-29 21:46:38 -0600910 status.check_patchwork_status(series, '1234', None, None, False, False,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700911 None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600912 lines = iter(terminal.GetPrintTestLines())
913 col = terminal.Color()
914 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
915 next(lines))
916 self.assertEqual(
917 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
918 bright=False),
919 next(lines))
920 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE, bright=False),
921 next(lines))
922
923 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
924 next(lines))
925 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -0600926 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -0600927 bright=False),
928 next(lines))
Simon Glass2112d072020-10-29 21:46:38 -0600929 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE, bright=False),
Simon Glass3db916d2020-10-29 21:46:35 -0600930 next(lines))
931 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -0600932 terminal.PrintLine(' Tested-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -0600933 bright=False),
934 next(lines))
Simon Glass2112d072020-10-29 21:46:38 -0600935 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE, bright=False),
Simon Glass3db916d2020-10-29 21:46:35 -0600936 next(lines))
937 self.assertEqual(
938 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
939 next(lines))
940 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
941 next(lines))
942 self.assertEqual(terminal.PrintLine(
Simon Glassd0a0a582020-10-29 21:46:36 -0600943 '1 new response available in patchwork (use -d to write them to a new branch)',
944 None), next(lines))
945
Simon Glassf9b03cf2020-11-03 13:54:14 -0700946 def _fake_patchwork3(self, url, subpath):
Simon Glassd0a0a582020-10-29 21:46:36 -0600947 """Fake Patchwork server for the function below
948
949 This handles accessing series, patches and comments, providing the data
950 in self.patches to the caller
Simon Glassf9b03cf2020-11-03 13:54:14 -0700951
952 Args:
953 url (str): URL of patchwork server
954 subpath (str): URL subpath to use
Simon Glassd0a0a582020-10-29 21:46:36 -0600955 """
956 re_series = re.match(r'series/(\d*)/$', subpath)
957 re_patch = re.match(r'patches/(\d*)/$', subpath)
958 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
959 if re_series:
960 series_num = re_series.group(1)
961 if series_num == '1234':
962 return {'patches': self.patches}
963 elif re_patch:
964 patch_num = int(re_patch.group(1))
965 patch = self.patches[patch_num - 1]
966 return patch
967 elif re_comments:
968 patch_num = int(re_comments.group(1))
969 patch = self.patches[patch_num - 1]
970 return patch.comments
971 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
972
973 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
974 def testCreateBranch(self):
975 """Test operation of create_branch()"""
976 repo = self.make_git_tree()
977 branch = 'first'
978 dest_branch = 'first2'
979 count = 2
980 gitdir = os.path.join(self.gitdir, '.git')
981
982 # Set up the test git tree. We use branch 'first' which has two commits
983 # in it
984 series = patchstream.get_metadata_for_list(branch, gitdir, count)
985 self.assertEqual(2, len(series.commits))
986
987 patch1 = status.Patch('1')
988 patch1.parse_subject('[1/2] %s' % series.commits[0].subject)
989 patch1.name = patch1.raw_subject
990 patch1.content = 'This is my patch content'
991 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
992
993 patch1.comments = [comment1a]
994
995 patch2 = status.Patch('2')
996 patch2.parse_subject('[2/2] %s' % series.commits[1].subject)
997 patch2.name = patch2.raw_subject
998 patch2.content = 'Some other patch content'
999 comment2a = {
1000 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1001 (self.mary, self.leb)}
1002 comment2b = {
1003 'content': 'Reviewed-by: %s' % self.fred}
1004 patch2.comments = [comment2a, comment2b]
1005
1006 # This test works by setting up patches for use by the fake Rest API
1007 # function _fake_patchwork3(). The fake patch comments above should
1008 # result in new review tags that are collected and added to the commits
1009 # created in the destination branch.
1010 self.patches = [patch1, patch2]
1011 count = 2
1012
1013 # Expected output:
1014 # 1 i2c: I2C things
1015 # + Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1016 # 2 spi: SPI fixes
1017 # + Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1018 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1019 # + Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1020 # 4 new responses available in patchwork
1021 # 4 responses added from patchwork into new branch 'first2'
1022 # <unittest.result.TestResult run=8 errors=0 failures=0>
1023
1024 terminal.SetPrintTestMode()
1025 status.check_patchwork_status(series, '1234', branch, dest_branch,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001026 False, False, None, self._fake_patchwork3,
1027 repo)
Simon Glassd0a0a582020-10-29 21:46:36 -06001028 lines = terminal.GetPrintTestLines()
1029 self.assertEqual(12, len(lines))
1030 self.assertEqual(
1031 "4 responses added from patchwork into new branch 'first2'",
1032 lines[11].text)
1033
1034 # Check that the destination branch has the new tags
1035 new_series = patchstream.get_metadata_for_list(dest_branch, gitdir,
1036 count)
1037 self.assertEqual(
1038 {'Reviewed-by': {self.joe}},
1039 new_series.commits[0].rtags)
1040 self.assertEqual(
1041 {'Tested-by': {self.leb},
1042 'Reviewed-by': {self.fred, self.mary}},
1043 new_series.commits[1].rtags)
1044
1045 # Now check the actual test of the first commit message. We expect to
1046 # see the new tags immediately below the old ones.
1047 stdout = patchstream.get_list(dest_branch, count=count, git_dir=gitdir)
1048 lines = iter([line.strip() for line in stdout.splitlines()
1049 if '-by:' in line])
1050
1051 # First patch should have the review tag
1052 self.assertEqual('Reviewed-by: %s' % self.joe, next(lines))
1053
1054 # Second patch should have the sign-off then the tested-by and two
1055 # reviewed-by tags
1056 self.assertEqual('Signed-off-by: %s' % self.leb, next(lines))
1057 self.assertEqual('Reviewed-by: %s' % self.fred, next(lines))
1058 self.assertEqual('Reviewed-by: %s' % self.mary, next(lines))
1059 self.assertEqual('Tested-by: %s' % self.leb, next(lines))
Simon Glassda8a2922020-10-29 21:46:37 -06001060
Simon Glass2112d072020-10-29 21:46:38 -06001061 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
Simon Glassda8a2922020-10-29 21:46:37 -06001062 def testParseSnippets(self):
1063 """Test parsing of review snippets"""
1064 text = '''Hi Fred,
1065
1066This is a comment from someone.
1067
1068Something else
1069
1070On some recent date, Fred wrote:
1071> This is why I wrote the patch
1072> so here it is
1073
1074Now a comment about the commit message
1075A little more to say
1076
1077Even more
1078
1079> diff --git a/file.c b/file.c
1080> Some more code
1081> Code line 2
1082> Code line 3
1083> Code line 4
1084> Code line 5
1085> Code line 6
1086> Code line 7
1087> Code line 8
1088> Code line 9
1089
1090And another comment
1091
1092> @@ -153,8 +143,13 @@ def CheckPatch(fname, show_types=False):
1093> further down on the file
1094> and more code
1095> +Addition here
1096> +Another addition here
1097> codey
1098> more codey
1099
1100and another thing in same file
1101
1102> @@ -253,8 +243,13 @@
1103> with no function context
1104
1105one more thing
1106
1107> diff --git a/tools/patman/main.py b/tools/patman/main.py
1108> +line of code
1109now a very long comment in a different file
1110line2
1111line3
1112line4
1113line5
1114line6
1115line7
1116line8
1117'''
1118 pstrm = PatchStream.process_text(text, True)
1119 self.assertEqual([], pstrm.commit.warn)
1120
1121 # We expect to the filename and up to 5 lines of code context before
1122 # each comment. The 'On xxx wrote:' bit should be removed.
1123 self.assertEqual(
1124 [['Hi Fred,',
1125 'This is a comment from someone.',
1126 'Something else'],
1127 ['> This is why I wrote the patch',
1128 '> so here it is',
1129 'Now a comment about the commit message',
1130 'A little more to say', 'Even more'],
1131 ['> File: file.c', '> Code line 5', '> Code line 6',
1132 '> Code line 7', '> Code line 8', '> Code line 9',
1133 'And another comment'],
1134 ['> File: file.c',
1135 '> Line: 153 / 143: def CheckPatch(fname, show_types=False):',
1136 '> and more code', '> +Addition here', '> +Another addition here',
1137 '> codey', '> more codey', 'and another thing in same file'],
1138 ['> File: file.c', '> Line: 253 / 243',
1139 '> with no function context', 'one more thing'],
1140 ['> File: tools/patman/main.py', '> +line of code',
1141 'now a very long comment in a different file',
1142 'line2', 'line3', 'line4', 'line5', 'line6', 'line7', 'line8']],
1143 pstrm.snippets)
Simon Glass2112d072020-10-29 21:46:38 -06001144
1145 @unittest.skipIf(not HAVE_PYGIT2, 'Missing python3-pygit2')
1146 def testReviewSnippets(self):
1147 """Test showing of review snippets"""
1148 def _to_submitter(who):
1149 m_who = re.match('(.*) <(.*)>', who)
1150 return {
1151 'name': m_who.group(1),
1152 'email': m_who.group(2)
1153 }
1154
1155 commit1 = Commit('abcd')
1156 commit1.subject = 'Subject 1'
1157 commit2 = Commit('ef12')
1158 commit2.subject = 'Subject 2'
1159
1160 patch1 = status.Patch('1')
1161 patch1.parse_subject('[1/2] Subject 1')
1162 patch1.name = patch1.raw_subject
1163 patch1.content = 'This is my patch content'
1164 comment1a = {'submitter': _to_submitter(self.joe),
1165 'content': '''Hi Fred,
1166
1167On some date Fred wrote:
1168
1169> diff --git a/file.c b/file.c
1170> Some code
1171> and more code
1172
1173Here is my comment above the above...
1174
1175
1176Reviewed-by: %s
1177''' % self.joe}
1178
1179 patch1.comments = [comment1a]
1180
1181 patch2 = status.Patch('2')
1182 patch2.parse_subject('[2/2] Subject 2')
1183 patch2.name = patch2.raw_subject
1184 patch2.content = 'Some other patch content'
1185 comment2a = {
1186 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1187 (self.mary, self.leb)}
1188 comment2b = {'submitter': _to_submitter(self.fred),
1189 'content': '''Hi Fred,
1190
1191On some date Fred wrote:
1192
1193> diff --git a/tools/patman/commit.py b/tools/patman/commit.py
1194> @@ -41,6 +41,9 @@ class Commit:
1195> self.rtags = collections.defaultdict(set)
1196> self.warn = []
1197>
1198> + def __str__(self):
1199> + return self.subject
1200> +
1201> def AddChange(self, version, info):
1202> """Add a new change line to the change list for a version.
1203>
1204A comment
1205
1206Reviewed-by: %s
1207''' % self.fred}
1208 patch2.comments = [comment2a, comment2b]
1209
1210 # This test works by setting up commits and patch for use by the fake
1211 # Rest API function _fake_patchwork2(). It calls various functions in
1212 # the status module after setting up tags in the commits, checking that
1213 # things behaves as expected
1214 self.commits = [commit1, commit2]
1215 self.patches = [patch1, patch2]
1216
1217 # Check that the output patches expectations:
1218 # 1 Subject 1
1219 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1220 # 2 Subject 2
1221 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1222 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1223 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1224 # 1 new response available in patchwork
1225
1226 series = Series()
1227 series.commits = [commit1, commit2]
1228 terminal.SetPrintTestMode()
1229 status.check_patchwork_status(series, '1234', None, None, False, True,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001230 None, self._fake_patchwork2)
Simon Glass2112d072020-10-29 21:46:38 -06001231 lines = iter(terminal.GetPrintTestLines())
1232 col = terminal.Color()
1233 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
1234 next(lines))
1235 self.assertEqual(
1236 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1237 next(lines))
1238 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE), next(lines))
1239
1240 self.assertEqual(terminal.PrintLine('Review: %s' % self.joe, col.RED),
1241 next(lines))
1242 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1243 self.assertEqual(terminal.PrintLine('', None), next(lines))
1244 self.assertEqual(terminal.PrintLine(' > File: file.c', col.MAGENTA),
1245 next(lines))
1246 self.assertEqual(terminal.PrintLine(' > Some code', col.MAGENTA),
1247 next(lines))
1248 self.assertEqual(terminal.PrintLine(' > and more code', col.MAGENTA),
1249 next(lines))
1250 self.assertEqual(terminal.PrintLine(
1251 ' Here is my comment above the above...', None), next(lines))
1252 self.assertEqual(terminal.PrintLine('', None), next(lines))
1253
1254 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
1255 next(lines))
1256 self.assertEqual(
1257 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1258 next(lines))
1259 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE),
1260 next(lines))
1261 self.assertEqual(
1262 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1263 next(lines))
1264 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
1265 next(lines))
1266 self.assertEqual(
1267 terminal.PrintLine(' + Tested-by: ', col.GREEN, newline=False),
1268 next(lines))
1269 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE),
1270 next(lines))
1271
1272 self.assertEqual(terminal.PrintLine('Review: %s' % self.fred, col.RED),
1273 next(lines))
1274 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1275 self.assertEqual(terminal.PrintLine('', None), next(lines))
1276 self.assertEqual(terminal.PrintLine(
1277 ' > File: tools/patman/commit.py', col.MAGENTA), next(lines))
1278 self.assertEqual(terminal.PrintLine(
1279 ' > Line: 41 / 41: class Commit:', col.MAGENTA), next(lines))
1280 self.assertEqual(terminal.PrintLine(
1281 ' > + return self.subject', col.MAGENTA), next(lines))
1282 self.assertEqual(terminal.PrintLine(
1283 ' > +', col.MAGENTA), next(lines))
1284 self.assertEqual(
1285 terminal.PrintLine(' > def AddChange(self, version, info):',
1286 col.MAGENTA),
1287 next(lines))
1288 self.assertEqual(terminal.PrintLine(
1289 ' > """Add a new change line to the change list for a version.',
1290 col.MAGENTA), next(lines))
1291 self.assertEqual(terminal.PrintLine(
1292 ' >', col.MAGENTA), next(lines))
1293 self.assertEqual(terminal.PrintLine(
1294 ' A comment', None), next(lines))
1295 self.assertEqual(terminal.PrintLine('', None), next(lines))
1296
1297 self.assertEqual(terminal.PrintLine(
1298 '4 new responses available in patchwork (use -d to write them to a new branch)',
1299 None), next(lines))