diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/patman/func_test.py | 1342 | ||||
| -rw-r--r-- | tools/patman/pytest.ini | 2 | ||||
| -rw-r--r-- | tools/patman/test/0000-cover-letter.patch | 23 | ||||
| -rw-r--r-- | tools/patman/test/0001-pci-Correct-cast-for-sandbox.patch | 51 | ||||
| -rw-r--r-- | tools/patman/test/0002-fdt-Correct-cast-for-sandbox-in-fdtdec_setup_mem_siz.patch | 85 | ||||
| -rw-r--r-- | tools/patman/test/test01.txt | 72 | ||||
| -rw-r--r-- | tools/patman/test_checkpatch.py | 526 | ||||
| -rw-r--r-- | tools/patman/test_common.py | 254 | ||||
| -rw-r--r-- | tools/patman/test_cseries.py | 3684 | ||||
| -rw-r--r-- | tools/patman/test_settings.py | 67 |
10 files changed, 0 insertions, 6106 deletions
diff --git a/tools/patman/func_test.py b/tools/patman/func_test.py deleted file mode 100644 index d029181765c..00000000000 --- a/tools/patman/func_test.py +++ /dev/null @@ -1,1342 +0,0 @@ -# -*- coding: utf-8 -*- -# SPDX-License-Identifier: GPL-2.0+ -# -# Copyright 2017 Google, Inc -# - -"""Functional tests for checking that patman behaves correctly""" - -import asyncio -import contextlib -import os -import pathlib -import re -import shutil -import sys -import unittest - -import pygit2 - -from u_boot_pylib import command -from u_boot_pylib import gitutil -from u_boot_pylib import terminal -from u_boot_pylib import tools - -from patman.commit import Commit -from patman import control -from patman import patchstream -from patman.patchstream import PatchStream -from patman import patchwork -from patman import send -from patman.series import Series -from patman import status -from patman.test_common import TestCommon - -PATMAN_DIR = pathlib.Path(__file__).parent -TEST_DATA_DIR = PATMAN_DIR / 'test/' - - -def directory_excursion(directory): - """Change directory to `directory` for a limited to the context block.""" - current = os.getcwd() - try: - os.chdir(directory) - yield - finally: - os.chdir(current) - - -class TestFunctional(unittest.TestCase, TestCommon): - """Functional tests for checking that patman behaves correctly""" - fred = 'Fred Bloggs <[email protected]>' - joe = 'Joe Bloggs <[email protected]>' - mary = 'Mary Bloggs <[email protected]>' - commits = None - patches = None - - def setUp(self): - TestCommon.setUp(self) - self.repo = None - self._patman_pathname = sys.argv[0] - self._patman_dir = os.path.dirname(os.path.realpath(sys.argv[0])) - - def tearDown(self): - TestCommon.tearDown(self) - - @staticmethod - def _get_path(fname): - """Get the path to a test file - - Args: - fname (str): Filename to obtain - - Returns: - str: Full path to file in the test directory - """ - return TEST_DATA_DIR / fname - - @classmethod - def _get_text(cls, fname): - """Read a file as text - - Args: - fname (str): Filename to read - - Returns: - str: Contents of file - """ - return open(cls._get_path(fname), encoding='utf-8').read() - - @classmethod - def _get_patch_name(cls, subject): - """Get the filename of a patch given its subject - - Args: - subject (str): Patch subject - - Returns: - str: Filename for that patch - """ - fname = re.sub('[ :]', '-', subject) - return fname.replace('--', '-') - - def _create_patches_for_test(self, series): - """Create patch files for use by tests - - This copies patch files from the test directory as needed by the series - - Args: - series (Series): Series containing commits to convert - - Returns: - tuple: - str: Cover-letter filename, or None if none - fname_list: list of str, each a patch filename - """ - cover_fname = None - fname_list = [] - for i, commit in enumerate(series.commits): - clean_subject = self._get_patch_name(commit.subject) - src_fname = '%04d-%s.patch' % (i + 1, clean_subject[:52]) - fname = os.path.join(self.tmpdir, src_fname) - shutil.copy(self._get_path(src_fname), fname) - fname_list.append(fname) - if series.get('cover'): - src_fname = '0000-cover-letter.patch' - cover_fname = os.path.join(self.tmpdir, src_fname) - fname = os.path.join(self.tmpdir, src_fname) - shutil.copy(self._get_path(src_fname), fname) - - return cover_fname, fname_list - - def test_basic(self): - """Tests the basic flow of patman - - This creates a series from some hard-coded patches build from a simple - tree with the following metadata in the top commit: - - Series-to: u-boot - Series-prefix: RFC - Series-postfix: some-branch - Series-cc: Stefan Brüns <[email protected]> - Cover-letter-cc: Lord Mëlchett <[email protected]> - Series-version: 3 - Patch-cc: fred - Series-process-log: sort, uniq - Series-changes: 4 - - Some changes - - Multi - line - change - - Commit-changes: 2 - - Changes only for this commit - - Cover-changes: 4 - - Some notes for the cover letter - - Cover-letter: - test: A test patch series - This is a test of how the cover - letter - works - END - - and this in the first commit: - - Commit-changes: 2 - - second revision change - - Series-notes: - some notes - about some things - from the first commit - END - - Commit-notes: - Some notes about - the first commit - END - - with the following commands: - - git log -n2 --reverse >/path/to/tools/patman/test/test01.txt - git format-patch --subject-prefix RFC --cover-letter HEAD~2 - mv 00* /path/to/tools/patman/test - - It checks these aspects: - - git log can be processed by patchstream - - emailing patches uses the correct command - - CC file has information on each commit - - cover letter has the expected text and subject - - each patch has the correct subject - - dry-run information prints out correctly - - unicode is handled correctly - - Series-to, Series-cc, Series-prefix, Series-postfix, Cover-letter - - Cover-letter-cc, Series-version, Series-changes, Series-notes - - Commit-notes - """ - process_tags = True - ignore_bad_tags = False - stefan = (b'Stefan Br\xc3\xbcns <[email protected]>' - .decode('utf-8')) - rick = 'Richard III <[email protected]>' - mel = b'Lord M\xc3\xablchett <[email protected]>'.decode('utf-8') - add_maintainers = [stefan, rick] - dry_run = True - in_reply_to = mel - count = 2 - alias = { - 'fdt': ['simon'], - 'u-boot': ['[email protected]'], - 'simon': [self.leb], - 'fred': [self.fred], - 'joe': [self.joe], - } - - text = self._get_text('test01.txt') - series = patchstream.get_metadata_for_test(text) - series.base_commit = Commit('1a44532') - series.branch = 'mybranch' - cover_fname, args = self._create_patches_for_test(series) - get_maintainer_script = str(pathlib.Path(__file__).parent.parent.parent - / 'get_maintainer.pl') + ' --norolestats' - with terminal.capture() as out: - patchstream.fix_patches(series, args) - if cover_fname and series.get('cover'): - patchstream.insert_cover_letter(cover_fname, series, count) - series.DoChecks() - cc_file = series.MakeCcFile(process_tags, cover_fname, - not ignore_bad_tags, add_maintainers, - None, get_maintainer_script, alias) - cmd = gitutil.email_patches( - series, cover_fname, args, dry_run, not ignore_bad_tags, - cc_file, alias, in_reply_to=in_reply_to, thread=None) - series.ShowActions(args, cmd, process_tags, alias) - cc_lines = tools.read_file(cc_file, binary=False).splitlines() - os.remove(cc_file) - - itr = iter(out[0].getvalue().splitlines()) - self.assertEqual('Cleaned %s patches' % len(series.commits), - next(itr)) - self.assertEqual('Change log missing for v2', next(itr)) - self.assertEqual('Change log missing for v3', next(itr)) - self.assertEqual('Change log for unknown version v4', next(itr)) - self.assertEqual("Alias 'pci' not found", next(itr)) - while next(itr) != 'Cc processing complete': - pass - self.assertIn('Dry run', next(itr)) - self.assertEqual('', next(itr)) - self.assertIn('Send a total of %d patches' % count, next(itr)) - prev = next(itr) - for i in range(len(series.commits)): - self.assertEqual(' %s' % args[i], prev) - while True: - prev = next(itr) - if 'Cc:' not in prev: - break - self.assertEqual('To: [email protected]', prev) - self.assertEqual('Cc: %s' % stefan, next(itr)) - self.assertEqual('Version: 3', next(itr)) - self.assertEqual('Prefix:\t RFC', next(itr)) - self.assertEqual('Postfix:\t some-branch', next(itr)) - self.assertEqual('Cover: 4 lines', next(itr)) - self.assertEqual(' Cc: %s' % self.fred, next(itr)) - self.assertEqual(' Cc: %s' % self.joe, next(itr)) - self.assertEqual(' Cc: %s' % self.leb, - next(itr)) - self.assertEqual(' Cc: %s' % mel, next(itr)) - self.assertEqual(' Cc: %s' % rick, next(itr)) - expected = ('Git command: git send-email --annotate ' - '--in-reply-to="%s" --to [email protected] ' - '--cc "%s" --cc-cmd "%s send --cc-cmd %s" %s %s' - % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname, - ' '.join(args))) - self.assertEqual(expected, next(itr)) - - self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)), cc_lines[0]) - self.assertEqual( - '%s %s\0%s\0%s\0%s\0%s' % (args[1], self.fred, self.joe, self.leb, - rick, stefan), - cc_lines[1]) - - expected = ''' -This is a test of how the cover -letter -works - -some notes -about some things -from the first commit - -Changes in v4: -- Multi - line - change -- Some changes -- Some notes for the cover letter -- fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base() - -Simon Glass (2): - pci: Correct cast for sandbox - fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base() - - cmd/pci.c | 3 ++- - fs/fat/fat.c | 1 + - lib/efi_loader/efi_memory.c | 1 + - lib/fdtdec.c | 3 ++- - 4 files changed, 6 insertions(+), 2 deletions(-) - ---\x20 -2.7.4 - -base-commit: 1a44532 -branch: mybranch -''' - lines = tools.read_file(cover_fname, binary=False).splitlines() - self.assertEqual( - 'Subject: [RFC PATCH some-branch v3 0/2] test: A test patch series', - lines[3]) - self.assertEqual(expected.splitlines(), lines[7:]) - - for i, fname in enumerate(args): - lines = tools.read_file(fname, binary=False).splitlines() - subject = [line for line in lines if line.startswith('Subject')] - self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count), - subject[0][:18]) - - # Check that we got our commit notes - start = 0 - expected = '' - - if i == 0: - start = 17 - expected = '''--- -Some notes about -the first commit - -(no changes since v2) - -Changes in v2: -- second revision change''' - elif i == 1: - start = 17 - expected = '''--- - -Changes in v4: -- Multi - line - change -- New -- Some changes - -Changes in v2: -- Changes only for this commit''' - - if expected: - expected = expected.splitlines() - self.assertEqual(expected, lines[start:(start+len(expected))]) - - def test_base_commit(self): - """Test adding a base commit with no cover letter""" - orig_text = self._get_text('test01.txt') - pos = orig_text.index( - 'commit 5ab48490f03051875ab13d288a4bf32b507d76fd') - text = orig_text[:pos] - series = patchstream.get_metadata_for_test(text) - series.base_commit = Commit('1a44532') - series.branch = 'mybranch' - cover_fname, args = self._create_patches_for_test(series) - self.assertFalse(cover_fname) - with terminal.capture() as out: - patchstream.fix_patches(series, args, insert_base_commit=True) - self.assertEqual('Cleaned 1 patch\n', out[0].getvalue()) - lines = tools.read_file(args[0], binary=False).splitlines() - pos = lines.index('-- ') - - # We expect these lines at the end: - # -- (with trailing space) - # 2.7.4 - # (empty) - # base-commit: xxx - # branch: xxx - self.assertEqual('base-commit: 1a44532', lines[pos + 3]) - self.assertEqual('branch: mybranch', lines[pos + 4]) - - def test_branch(self): - """Test creating patches from a branch""" - repo = self.make_git_tree() - target = repo.lookup_reference('refs/heads/first') - # pylint doesn't seem to find this - # pylint: disable=E1101 - self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE) - control.setup() - orig_dir = os.getcwd() - try: - os.chdir(self.tmpdir) - - # Check that it can detect the current branch - self.assertEqual(2, gitutil.count_commits_to_branch(None)) - col = terminal.Color() - with terminal.capture() as _: - _, cover_fname, patch_files = send.prepare_patches( - col, branch=None, count=-1, start=0, end=0, - ignore_binary=False, signoff=True) - self.assertIsNone(cover_fname) - self.assertEqual(2, len(patch_files)) - - # Check that it can detect a different branch - self.assertEqual(3, gitutil.count_commits_to_branch('second')) - with terminal.capture() as _: - _, cover_fname, patch_files = send.prepare_patches( - col, branch='second', count=-1, start=0, end=0, - ignore_binary=False, signoff=True) - self.assertIsNotNone(cover_fname) - self.assertEqual(3, len(patch_files)) - - cover = tools.read_file(cover_fname, binary=False) - lines = cover.splitlines()[-2:] - base = repo.lookup_reference('refs/heads/base').target - self.assertEqual(f'base-commit: {base}', lines[0]) - self.assertEqual('branch: second', lines[1]) - - # Make sure that the base-commit is not present when it is in the - # cover letter - for fname in patch_files: - self.assertNotIn(b'base-commit:', tools.read_file(fname)) - - # Check that it can skip patches at the end - with terminal.capture() as _: - _, cover_fname, patch_files = send.prepare_patches( - col, branch='second', count=-1, start=0, end=1, - ignore_binary=False, signoff=True) - self.assertIsNotNone(cover_fname) - self.assertEqual(2, len(patch_files)) - - cover = tools.read_file(cover_fname, binary=False) - lines = cover.splitlines()[-2:] - base2 = repo.lookup_reference('refs/heads/second') - ref = base2.peel(pygit2.GIT_OBJ_COMMIT).parents[0].parents[0].id - self.assertEqual(f'base-commit: {ref}', lines[0]) - self.assertEqual('branch: second', lines[1]) - finally: - os.chdir(orig_dir) - - def test_custom_get_maintainer_script(self): - """Validate that a custom get_maintainer script gets used.""" - self.make_git_tree() - with directory_excursion(self.tmpdir): - # Setup git. - os.environ['GIT_CONFIG_GLOBAL'] = '/dev/null' - os.environ['GIT_CONFIG_SYSTEM'] = '/dev/null' - tools.run('git', 'config', 'user.name', 'Dummy') - tools.run('git', 'config', 'user.email', '[email protected]') - tools.run('git', 'branch', 'upstream') - tools.run('git', 'branch', '--set-upstream-to=upstream') - - # Setup patman configuration. - tools.write_file('.patman', '[settings]\n' - 'get_maintainer_script: dummy-script.sh\n' - 'check_patch: False\n' - 'add_maintainers: True\n', binary=False) - tools.write_file('dummy-script.sh', - '#!/usr/bin/env python3\n' - 'print("[email protected]")\n', binary=False) - os.chmod('dummy-script.sh', 0x555) - tools.run('git', 'add', '.') - tools.run('git', 'commit', '-m', 'new commit') - - # Finally, do the test - with terminal.capture(): - output = tools.run(PATMAN_DIR / 'patman', '--dry-run') - # Assert the email address is part of the dry-run - # output. - self.assertIn('[email protected]', output) - - def test_tags(self): - """Test collection of tags in a patchstream""" - text = '''This is a patch - -Signed-off-by: Terminator -Reviewed-by: %s -Reviewed-by: %s -Tested-by: %s -''' % (self.joe, self.mary, self.leb) - pstrm = PatchStream.process_text(text) - self.assertEqual(pstrm.commit.rtags, { - 'Reviewed-by': {self.joe, self.mary}, - 'Tested-by': {self.leb}}) - - def test_invalid_tag(self): - """Test invalid tag in a patchstream""" - text = '''This is a patch - -Serie-version: 2 -''' - with self.assertRaises(ValueError) as exc: - PatchStream.process_text(text) - self.assertEqual("Line 3: Invalid tag = 'Serie-version: 2'", - str(exc.exception)) - - def test_missing_end(self): - """Test a missing END tag""" - text = '''This is a patch - -Cover-letter: -This is the title -missing END after this line -Signed-off-by: Fred -''' - pstrm = PatchStream.process_text(text) - self.assertEqual(["Missing 'END' in section 'cover'"], - pstrm.commit.warn) - - def test_missing_blank_line(self): - """Test a missing blank line after a tag""" - text = '''This is a patch - -Series-changes: 2 -- First line of changes -- Missing blank line after this line -Signed-off-by: Fred -''' - pstrm = PatchStream.process_text(text) - self.assertEqual(["Missing 'blank line' in section 'Series-changes'"], - pstrm.commit.warn) - - def test_invalid_commit_tag(self): - """Test an invalid Commit-xxx tag""" - text = '''This is a patch - -Commit-fred: testing -''' - pstrm = PatchStream.process_text(text) - self.assertEqual(["Line 3: Ignoring Commit-fred"], pstrm.commit.warn) - - def test_self_test(self): - """Test a tested by tag by this user""" - test_line = 'Tested-by: %[email protected]' % os.getenv('USER') - text = '''This is a patch - -%s -''' % test_line - pstrm = PatchStream.process_text(text) - self.assertEqual(["Ignoring '%s'" % test_line], pstrm.commit.warn) - - def test_space_before_tab(self): - """Test a space before a tab""" - text = '''This is a patch - -+ \tSomething -''' - pstrm = PatchStream.process_text(text) - self.assertEqual(["Line 3/0 has space before tab"], pstrm.commit.warn) - - def test_lines_after_test(self): - """Test detecting lines after TEST= line""" - text = '''This is a patch - -TEST=sometest -more lines -here -''' - pstrm = PatchStream.process_text(text) - self.assertEqual(["Found 2 lines after TEST="], pstrm.commit.warn) - - def test_blank_line_at_end(self): - """Test detecting a blank line at the end of a file""" - text = '''This is a patch - -diff --git a/lib/fdtdec.c b/lib/fdtdec.c -index c072e54..942244f 100644 ---- a/lib/fdtdec.c -+++ b/lib/fdtdec.c -@@ -1200,7 +1200,8 @@ int fdtdec_setup_mem_size_base(void) - \t} - - \tgd->ram_size = (phys_size_t)(res.end - res.start + 1); -- debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size); -+ debug("%s: Initial DRAM size %llx\n", __func__, -+ (unsigned long long)gd->ram_size); -+ -diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c - --- -2.7.4 - - ''' - pstrm = PatchStream.process_text(text) - self.assertEqual( - ["Found possible blank line(s) at end of file 'lib/fdtdec.c'"], - pstrm.commit.warn) - - def test_no_upstream(self): - """Test CountCommitsToBranch when there is no upstream""" - repo = self.make_git_tree() - target = repo.lookup_reference('refs/heads/base') - # pylint doesn't seem to find this - # pylint: disable=E1101 - self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE) - - # Check that it can detect the current branch - orig_dir = os.getcwd() - try: - os.chdir(self.gitdir) - with self.assertRaises(ValueError) as exc: - gitutil.count_commits_to_branch(None) - self.assertIn( - "Failed to determine upstream: fatal: no upstream configured for branch 'base'", - str(exc.exception)) - finally: - os.chdir(orig_dir) - - def run_patman(self, *args): - """Run patman using the provided arguments - - This runs the patman executable from scratch, as opposed to calling - the control.do_patman() function. - - Args: - args (list of str): Arguments to pass (excluding argv[0]) - - Return: - CommandResult: Result of execution - """ - all_args = [self._patman_pathname] + list(args) - return command.run_one(*all_args, capture=True, capture_stderr=True) - - def test_full_help(self): - """Test getting full help""" - command.TEST_RESULT = None - result = self.run_patman('-H') - help_file = os.path.join(self._patman_dir, 'README.rst') - # Remove possible extraneous strings - extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n' - gothelp = result.stdout.replace(extra, '') - self.assertEqual(len(gothelp), os.path.getsize(help_file)) - self.assertEqual(0, len(result.stderr)) - self.assertEqual(0, result.return_code) - - def test_help(self): - """Test getting help with commands and arguments""" - command.TEST_RESULT = None - result = self.run_patman('-h') - self.assertTrue(len(result.stdout) > 1000) - self.assertEqual(0, len(result.stderr)) - self.assertEqual(0, result.return_code) - - @staticmethod - def _fake_patchwork(subpath): - """Fake Patchwork server for the function below - - This handles accessing a series, providing a list consisting of a - single patch - - Args: - subpath (str): URL subpath to use - """ - re_series = re.match(r'series/(\d*)/$', subpath) - if re_series: - series_num = re_series.group(1) - if series_num == '1234': - return {'patches': [ - {'id': '1', 'name': 'Some patch'}]} - raise ValueError('Fake Patchwork does not understand: %s' % subpath) - - def test_status_mismatch(self): - """Test Patchwork patches not matching the series""" - pwork = patchwork.Patchwork.for_testing(self._fake_patchwork) - with terminal.capture() as (_, err): - loop = asyncio.get_event_loop() - _, patches = loop.run_until_complete(status.check_status(1234, - pwork)) - status.check_patch_count(0, len(patches)) - self.assertIn('Warning: Patchwork reports 1 patches, series has 0', - err.getvalue()) - - def test_status_read_patch(self): - """Test handling a single patch in Patchwork""" - pwork = patchwork.Patchwork.for_testing(self._fake_patchwork) - loop = asyncio.get_event_loop() - _, patches = loop.run_until_complete(status.check_status(1234, pwork)) - self.assertEqual(1, len(patches)) - patch = patches[0] - self.assertEqual('1', patch.id) - self.assertEqual('Some patch', patch.raw_subject) - - def test_parse_subject(self): - """Test parsing of the patch subject""" - patch = patchwork.Patch('1') - - # Simple patch not in a series - patch.parse_subject('Testing') - self.assertEqual('Testing', patch.raw_subject) - self.assertEqual('Testing', patch.subject) - self.assertEqual(1, patch.seq) - self.assertEqual(1, patch.count) - self.assertEqual(None, patch.prefix) - self.assertEqual(None, patch.version) - - # First patch in a series - patch.parse_subject('[1/2] Testing') - self.assertEqual('[1/2] Testing', patch.raw_subject) - self.assertEqual('Testing', patch.subject) - self.assertEqual(1, patch.seq) - self.assertEqual(2, patch.count) - self.assertEqual(None, patch.prefix) - self.assertEqual(None, patch.version) - - # Second patch in a series - patch.parse_subject('[2/2] Testing') - self.assertEqual('Testing', patch.subject) - self.assertEqual(2, patch.seq) - self.assertEqual(2, patch.count) - self.assertEqual(None, patch.prefix) - self.assertEqual(None, patch.version) - - # With PATCH prefix - patch.parse_subject('[PATCH,2/5] Testing') - self.assertEqual('Testing', patch.subject) - self.assertEqual(2, patch.seq) - self.assertEqual(5, patch.count) - self.assertEqual('PATCH', patch.prefix) - self.assertEqual(None, patch.version) - - # RFC patch - patch.parse_subject('[RFC,3/7] Testing') - self.assertEqual('Testing', patch.subject) - self.assertEqual(3, patch.seq) - self.assertEqual(7, patch.count) - self.assertEqual('RFC', patch.prefix) - self.assertEqual(None, patch.version) - - # Version patch - patch.parse_subject('[v2,3/7] Testing') - self.assertEqual('Testing', patch.subject) - self.assertEqual(3, patch.seq) - self.assertEqual(7, patch.count) - self.assertEqual(None, patch.prefix) - self.assertEqual('v2', patch.version) - - # All fields - patch.parse_subject('[RESEND,v2,3/7] Testing') - self.assertEqual('Testing', patch.subject) - self.assertEqual(3, patch.seq) - self.assertEqual(7, patch.count) - self.assertEqual('RESEND', patch.prefix) - self.assertEqual('v2', patch.version) - - # RFC only - patch.parse_subject('[RESEND] Testing') - self.assertEqual('Testing', patch.subject) - self.assertEqual(1, patch.seq) - self.assertEqual(1, patch.count) - self.assertEqual('RESEND', patch.prefix) - self.assertEqual(None, patch.version) - - def test_compare_series(self): - """Test operation of compare_with_series()""" - commit1 = Commit('abcd') - commit1.subject = 'Subject 1' - commit2 = Commit('ef12') - commit2.subject = 'Subject 2' - commit3 = Commit('3456') - commit3.subject = 'Subject 2' - - patch1 = patchwork.Patch('1') - patch1.subject = 'Subject 1' - patch2 = patchwork.Patch('2') - patch2.subject = 'Subject 2' - patch3 = patchwork.Patch('3') - patch3.subject = 'Subject 2' - - series = Series() - series.commits = [commit1] - patches = [patch1] - patch_for_commit, commit_for_patch, warnings = ( - status.compare_with_series(series, patches)) - self.assertEqual(1, len(patch_for_commit)) - self.assertEqual(patch1, patch_for_commit[0]) - self.assertEqual(1, len(commit_for_patch)) - self.assertEqual(commit1, commit_for_patch[0]) - - series.commits = [commit1] - patches = [patch1, patch2] - patch_for_commit, commit_for_patch, warnings = ( - status.compare_with_series(series, patches)) - self.assertEqual(1, len(patch_for_commit)) - self.assertEqual(patch1, patch_for_commit[0]) - self.assertEqual(1, len(commit_for_patch)) - self.assertEqual(commit1, commit_for_patch[0]) - self.assertEqual(["Cannot find commit for patch 2 ('Subject 2')"], - warnings) - - series.commits = [commit1, commit2] - patches = [patch1] - patch_for_commit, commit_for_patch, warnings = ( - status.compare_with_series(series, patches)) - self.assertEqual(1, len(patch_for_commit)) - self.assertEqual(patch1, patch_for_commit[0]) - self.assertEqual(1, len(commit_for_patch)) - self.assertEqual(commit1, commit_for_patch[0]) - self.assertEqual(["Cannot find patch for commit 2 ('Subject 2')"], - warnings) - - series.commits = [commit1, commit2, commit3] - patches = [patch1, patch2] - patch_for_commit, commit_for_patch, warnings = ( - status.compare_with_series(series, patches)) - self.assertEqual(2, len(patch_for_commit)) - self.assertEqual(patch1, patch_for_commit[0]) - self.assertEqual(patch2, patch_for_commit[1]) - self.assertEqual(1, len(commit_for_patch)) - self.assertEqual(commit1, commit_for_patch[0]) - self.assertEqual(["Cannot find patch for commit 3 ('Subject 2')", - "Multiple commits match patch 2 ('Subject 2'):\n" - ' Subject 2\n Subject 2'], - warnings) - - series.commits = [commit1, commit2] - patches = [patch1, patch2, patch3] - patch_for_commit, commit_for_patch, warnings = ( - status.compare_with_series(series, patches)) - self.assertEqual(1, len(patch_for_commit)) - self.assertEqual(patch1, patch_for_commit[0]) - self.assertEqual(2, len(commit_for_patch)) - self.assertEqual(commit1, commit_for_patch[0]) - self.assertEqual(["Multiple patches match commit 2 ('Subject 2'):\n" - ' Subject 2\n Subject 2', - "Cannot find commit for patch 3 ('Subject 2')"], - warnings) - - def _fake_patchwork2(self, subpath): - """Fake Patchwork server for the function below - - This handles accessing series, patches and comments, providing the data - in self.patches to the caller - - Args: - subpath (str): URL subpath to use - """ - re_series = re.match(r'series/(\d*)/$', subpath) - re_patch = re.match(r'patches/(\d*)/$', subpath) - re_comments = re.match(r'patches/(\d*)/comments/$', subpath) - if re_series: - series_num = re_series.group(1) - if series_num == '1234': - return {'patches': self.patches} - elif re_patch: - patch_num = int(re_patch.group(1)) - patch = self.patches[patch_num - 1] - return patch - elif re_comments: - patch_num = int(re_comments.group(1)) - patch = self.patches[patch_num - 1] - return patch.comments - raise ValueError('Fake Patchwork does not understand: %s' % subpath) - - def test_find_new_responses(self): - """Test operation of find_new_responses()""" - commit1 = Commit('abcd') - commit1.subject = 'Subject 1' - commit2 = Commit('ef12') - commit2.subject = 'Subject 2' - - patch1 = patchwork.Patch('1') - patch1.parse_subject('[1/2] Subject 1') - patch1.name = patch1.raw_subject - patch1.content = 'This is my patch content' - comment1a = {'content': 'Reviewed-by: %s\n' % self.joe} - - patch1.comments = [comment1a] - - patch2 = patchwork.Patch('2') - patch2.parse_subject('[2/2] Subject 2') - patch2.name = patch2.raw_subject - patch2.content = 'Some other patch content' - comment2a = { - 'content': 'Reviewed-by: %s\nTested-by: %s\n' % - (self.mary, self.leb)} - comment2b = {'content': 'Reviewed-by: %s' % self.fred} - patch2.comments = [comment2a, comment2b] - - # This test works by setting up commits and patch for use by the fake - # Rest API function _fake_patchwork2(). It calls various functions in - # the status module after setting up tags in the commits, checking that - # things behaves as expected - self.commits = [commit1, commit2] - self.patches = [patch1, patch2] - - # Check that the tags are picked up on the first patch - new_rtags, _ = status.process_reviews(patch1.content, patch1.comments, - commit1.rtags) - self.assertEqual(new_rtags, {'Reviewed-by': {self.joe}}) - - # Now the second patch - new_rtags, _ = status.process_reviews(patch2.content, patch2.comments, - commit2.rtags) - self.assertEqual(new_rtags, { - 'Reviewed-by': {self.mary, self.fred}, - 'Tested-by': {self.leb}}) - - # Now add some tags to the commit, which means they should not appear as - # 'new' tags when scanning comments - commit1.rtags = {'Reviewed-by': {self.joe}} - new_rtags, _ = status.process_reviews(patch1.content, patch1.comments, - commit1.rtags) - self.assertEqual(new_rtags, {}) - - # For the second commit, add Ed and Fred, so only Mary should be left - commit2.rtags = { - 'Tested-by': {self.leb}, - 'Reviewed-by': {self.fred}} - new_rtags, _ = status.process_reviews(patch2.content, patch2.comments, - commit2.rtags) - self.assertEqual(new_rtags, {'Reviewed-by': {self.mary}}) - - # Check that the output patches expectations: - # 1 Subject 1 - # Reviewed-by: Joe Bloggs <[email protected]> - # 2 Subject 2 - # Tested-by: Lord Edmund Blackaddër <[email protected]> - # Reviewed-by: Fred Bloggs <[email protected]> - # + Reviewed-by: Mary Bloggs <[email protected]> - # 1 new response available in patchwork - - series = Series() - series.commits = [commit1, commit2] - terminal.set_print_test_mode() - pwork = patchwork.Patchwork.for_testing(self._fake_patchwork2) - status.check_and_show_status(series, '1234', None, None, False, False, - False, pwork) - itr = iter(terminal.get_print_test_lines()) - col = terminal.Color() - self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.YELLOW), - next(itr)) - self.assertEqual( - terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False, - bright=False), - next(itr)) - self.assertEqual(terminal.PrintLine(self.joe, col.WHITE, bright=False), - next(itr)) - - self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.YELLOW), - next(itr)) - self.assertEqual( - terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False, - bright=False), - next(itr)) - self.assertEqual(terminal.PrintLine(self.fred, col.WHITE, - bright=False), next(itr)) - self.assertEqual( - terminal.PrintLine(' Tested-by: ', col.GREEN, newline=False, - bright=False), - next(itr)) - self.assertEqual(terminal.PrintLine(self.leb, col.WHITE, bright=False), - next(itr)) - self.assertEqual( - terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False), - next(itr)) - self.assertEqual(terminal.PrintLine(self.mary, col.WHITE), - next(itr)) - self.assertEqual(terminal.PrintLine( - '1 new response available in patchwork (use -d to write them to a new branch)', - None), next(itr)) - - def _fake_patchwork3(self, subpath): - """Fake Patchwork server for the function below - - This handles accessing series, patches and comments, providing the data - in self.patches to the caller - - Args: - subpath (str): URL subpath to use - """ - re_series = re.match(r'series/(\d*)/$', subpath) - re_patch = re.match(r'patches/(\d*)/$', subpath) - re_comments = re.match(r'patches/(\d*)/comments/$', subpath) - if re_series: - series_num = re_series.group(1) - if series_num == '1234': - return {'patches': self.patches} - elif re_patch: - patch_num = int(re_patch.group(1)) - patch = self.patches[patch_num - 1] - return patch - elif re_comments: - patch_num = int(re_comments.group(1)) - patch = self.patches[patch_num - 1] - return patch.comments - raise ValueError('Fake Patchwork does not understand: %s' % subpath) - - def test_create_branch(self): - """Test operation of create_branch()""" - repo = self.make_git_tree() - branch = 'first' - dest_branch = 'first2' - count = 2 - gitdir = self.gitdir - - # Set up the test git tree. We use branch 'first' which has two commits - # in it - series = patchstream.get_metadata_for_list(branch, gitdir, count) - self.assertEqual(2, len(series.commits)) - - patch1 = patchwork.Patch('1') - patch1.parse_subject('[1/2] %s' % series.commits[0].subject) - patch1.name = patch1.raw_subject - patch1.content = 'This is my patch content' - comment1a = {'content': 'Reviewed-by: %s\n' % self.joe} - - patch1.comments = [comment1a] - - patch2 = patchwork.Patch('2') - patch2.parse_subject('[2/2] %s' % series.commits[1].subject) - patch2.name = patch2.raw_subject - patch2.content = 'Some other patch content' - comment2a = { - 'content': 'Reviewed-by: %s\nTested-by: %s\n' % - (self.mary, self.leb)} - comment2b = { - 'content': 'Reviewed-by: %s' % self.fred} - patch2.comments = [comment2a, comment2b] - - # This test works by setting up patches for use by the fake Rest API - # function _fake_patchwork3(). The fake patch comments above should - # result in new review tags that are collected and added to the commits - # created in the destination branch. - self.patches = [patch1, patch2] - count = 2 - - # Expected output: - # 1 i2c: I2C things - # + Reviewed-by: Joe Bloggs <[email protected]> - # 2 spi: SPI fixes - # + Reviewed-by: Fred Bloggs <[email protected]> - # + Reviewed-by: Mary Bloggs <[email protected]> - # + Tested-by: Lord Edmund Blackaddër <[email protected]> - # 4 new responses available in patchwork - # 4 responses added from patchwork into new branch 'first2' - # <unittest.result.TestResult run=8 errors=0 failures=0> - - terminal.set_print_test_mode() - pwork = patchwork.Patchwork.for_testing(self._fake_patchwork3) - status.check_and_show_status( - series, '1234', branch, dest_branch, False, False, False, pwork, - repo) - lines = terminal.get_print_test_lines() - self.assertEqual(12, len(lines)) - self.assertEqual( - "4 responses added from patchwork into new branch 'first2'", - lines[11].text) - - # Check that the destination branch has the new tags - new_series = patchstream.get_metadata_for_list(dest_branch, gitdir, - count) - self.assertEqual( - {'Reviewed-by': {self.joe}}, - new_series.commits[0].rtags) - self.assertEqual( - {'Tested-by': {self.leb}, - 'Reviewed-by': {self.fred, self.mary}}, - new_series.commits[1].rtags) - - # Now check the actual test of the first commit message. We expect to - # see the new tags immediately below the old ones. - stdout = patchstream.get_list(dest_branch, count=count, git_dir=gitdir) - itr = iter([line.strip() for line in stdout.splitlines() - if '-by:' in line]) - - # First patch should have the review tag - self.assertEqual('Reviewed-by: %s' % self.joe, next(itr)) - - # Second patch should have the sign-off then the tested-by and two - # reviewed-by tags - self.assertEqual('Signed-off-by: %s' % self.leb, next(itr)) - self.assertEqual('Reviewed-by: %s' % self.fred, next(itr)) - self.assertEqual('Reviewed-by: %s' % self.mary, next(itr)) - self.assertEqual('Tested-by: %s' % self.leb, next(itr)) - - def test_parse_snippets(self): - """Test parsing of review snippets""" - text = '''Hi Fred, - -This is a comment from someone. - -Something else - -On some recent date, Fred wrote: -> This is why I wrote the patch -> so here it is - -Now a comment about the commit message -A little more to say - -Even more - -> diff --git a/file.c b/file.c -> Some more code -> Code line 2 -> Code line 3 -> Code line 4 -> Code line 5 -> Code line 6 -> Code line 7 -> Code line 8 -> Code line 9 - -And another comment - -> @@ -153,8 +143,13 @@ def check_patch(fname, show_types=False): -> further down on the file -> and more code -> +Addition here -> +Another addition here -> codey -> more codey - -and another thing in same file - -> @@ -253,8 +243,13 @@ -> with no function context - -one more thing - -> diff --git a/tools/patman/main.py b/tools/patman/main.py -> +line of code -now a very long comment in a different file -line2 -line3 -line4 -line5 -line6 -line7 -line8 -''' - pstrm = PatchStream.process_text(text, True) - self.assertEqual([], pstrm.commit.warn) - - # We expect to the filename and up to 5 lines of code context before - # each comment. The 'On xxx wrote:' bit should be removed. - self.assertEqual( - [['Hi Fred,', - 'This is a comment from someone.', - 'Something else'], - ['> This is why I wrote the patch', - '> so here it is', - 'Now a comment about the commit message', - 'A little more to say', 'Even more'], - ['> File: file.c', '> Code line 5', '> Code line 6', - '> Code line 7', '> Code line 8', '> Code line 9', - 'And another comment'], - ['> File: file.c', - '> Line: 153 / 143: def check_patch(fname, show_types=False):', - '> and more code', '> +Addition here', - '> +Another addition here', '> codey', '> more codey', - 'and another thing in same file'], - ['> File: file.c', '> Line: 253 / 243', - '> with no function context', 'one more thing'], - ['> File: tools/patman/main.py', '> +line of code', - 'now a very long comment in a different file', - 'line2', 'line3', 'line4', 'line5', 'line6', 'line7', 'line8']], - pstrm.snippets) - - def test_review_snippets(self): - """Test showing of review snippets""" - def _to_submitter(who): - m_who = re.match('(.*) <(.*)>', who) - return { - 'name': m_who.group(1), - 'email': m_who.group(2) - } - - commit1 = Commit('abcd') - commit1.subject = 'Subject 1' - commit2 = Commit('ef12') - commit2.subject = 'Subject 2' - - patch1 = patchwork.Patch('1') - patch1.parse_subject('[1/2] Subject 1') - patch1.name = patch1.raw_subject - patch1.content = 'This is my patch content' - comment1a = {'submitter': _to_submitter(self.joe), - 'content': '''Hi Fred, - -On some date Fred wrote: - -> diff --git a/file.c b/file.c -> Some code -> and more code - -Here is my comment above the above... - - -Reviewed-by: %s -''' % self.joe} - - patch1.comments = [comment1a] - - patch2 = patchwork.Patch('2') - patch2.parse_subject('[2/2] Subject 2') - patch2.name = patch2.raw_subject - patch2.content = 'Some other patch content' - comment2a = { - 'content': 'Reviewed-by: %s\nTested-by: %s\n' % - (self.mary, self.leb)} - comment2b = {'submitter': _to_submitter(self.fred), - 'content': '''Hi Fred, - -On some date Fred wrote: - -> diff --git a/tools/patman/commit.py b/tools/patman/commit.py -> @@ -41,6 +41,9 @@ class Commit: -> self.rtags = collections.defaultdict(set) -> self.warn = [] -> -> + def __str__(self): -> + return self.subject -> + -> def add_change(self, version, info): -> """Add a new change line to the change list for a version. -> -A comment - -Reviewed-by: %s -''' % self.fred} - patch2.comments = [comment2a, comment2b] - - # This test works by setting up commits and patch for use by the fake - # Rest API function _fake_patchwork2(). It calls various functions in - # the status module after setting up tags in the commits, checking that - # things behaves as expected - self.commits = [commit1, commit2] - self.patches = [patch1, patch2] - - # Check that the output patches expectations: - # 1 Subject 1 - # Reviewed-by: Joe Bloggs <[email protected]> - # 2 Subject 2 - # Tested-by: Lord Edmund Blackaddër <[email protected]> - # Reviewed-by: Fred Bloggs <[email protected]> - # + Reviewed-by: Mary Bloggs <[email protected]> - # 1 new response available in patchwork - - series = Series() - series.commits = [commit1, commit2] - terminal.set_print_test_mode() - pwork = patchwork.Patchwork.for_testing(self._fake_patchwork2) - status.check_and_show_status( - series, '1234', None, None, False, True, False, pwork) - itr = iter(terminal.get_print_test_lines()) - col = terminal.Color() - self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.YELLOW), - next(itr)) - self.assertEqual( - terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False), - next(itr)) - self.assertEqual(terminal.PrintLine(self.joe, col.WHITE), next(itr)) - - self.assertEqual(terminal.PrintLine('Review: %s' % self.joe, col.RED), - next(itr)) - self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(itr)) - self.assertEqual(terminal.PrintLine('', None), next(itr)) - self.assertEqual(terminal.PrintLine(' > File: file.c', col.MAGENTA), - next(itr)) - self.assertEqual(terminal.PrintLine(' > Some code', col.MAGENTA), - next(itr)) - self.assertEqual(terminal.PrintLine(' > and more code', - col.MAGENTA), - next(itr)) - self.assertEqual(terminal.PrintLine( - ' Here is my comment above the above...', None), next(itr)) - self.assertEqual(terminal.PrintLine('', None), next(itr)) - - self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.YELLOW), - next(itr)) - self.assertEqual( - terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False), - next(itr)) - self.assertEqual(terminal.PrintLine(self.fred, col.WHITE), - next(itr)) - self.assertEqual( - terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False), - next(itr)) - self.assertEqual(terminal.PrintLine(self.mary, col.WHITE), - next(itr)) - self.assertEqual( - terminal.PrintLine(' + Tested-by: ', col.GREEN, newline=False), - next(itr)) - self.assertEqual(terminal.PrintLine(self.leb, col.WHITE), - next(itr)) - - self.assertEqual(terminal.PrintLine('Review: %s' % self.fred, col.RED), - next(itr)) - self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(itr)) - self.assertEqual(terminal.PrintLine('', None), next(itr)) - self.assertEqual(terminal.PrintLine( - ' > File: tools/patman/commit.py', col.MAGENTA), next(itr)) - self.assertEqual(terminal.PrintLine( - ' > Line: 41 / 41: class Commit:', col.MAGENTA), next(itr)) - self.assertEqual(terminal.PrintLine( - ' > + return self.subject', col.MAGENTA), next(itr)) - self.assertEqual(terminal.PrintLine( - ' > +', col.MAGENTA), next(itr)) - self.assertEqual( - terminal.PrintLine( - ' > def add_change(self, version, info):', - col.MAGENTA), - next(itr)) - self.assertEqual(terminal.PrintLine( - ' > """Add a new change line to the change list for a version.', - col.MAGENTA), next(itr)) - self.assertEqual(terminal.PrintLine( - ' >', col.MAGENTA), next(itr)) - self.assertEqual(terminal.PrintLine( - ' A comment', None), next(itr)) - self.assertEqual(terminal.PrintLine('', None), next(itr)) - - self.assertEqual(terminal.PrintLine( - '4 new responses available in patchwork (use -d to write them to a new branch)', - None), next(itr)) - - def test_insert_tags(self): - """Test inserting of review tags""" - msg = '''first line -second line.''' - tags = [ - 'Reviewed-by: Bin Meng <[email protected]>', - 'Tested-by: Bin Meng <[email protected]>' - ] - signoff = 'Signed-off-by: Simon Glass <[email protected]>' - tag_str = '\n'.join(tags) - - new_msg = patchstream.insert_tags(msg, tags) - self.assertEqual(msg + '\n\n' + tag_str, new_msg) - - new_msg = patchstream.insert_tags(msg + '\n', tags) - self.assertEqual(msg + '\n\n' + tag_str, new_msg) - - msg += '\n\n' + signoff - new_msg = patchstream.insert_tags(msg, tags) - self.assertEqual(msg + '\n' + tag_str, new_msg) diff --git a/tools/patman/pytest.ini b/tools/patman/pytest.ini deleted file mode 100644 index df3eb518d0f..00000000000 --- a/tools/patman/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -addopts = --doctest-modules diff --git a/tools/patman/test/0000-cover-letter.patch b/tools/patman/test/0000-cover-letter.patch deleted file mode 100644 index c99e635623f..00000000000 --- a/tools/patman/test/0000-cover-letter.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 5ab48490f03051875ab13d288a4bf32b507d76fd Mon Sep 17 00:00:00 2001 -From: Simon Glass <[email protected]> -Date: Sat, 27 May 2017 20:52:11 -0600 -Subject: [RFC 0/2] *** SUBJECT HERE *** -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -*** BLURB HERE *** - -Simon Glass (2): - pci: Correct cast for sandbox - fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base() - - cmd/pci.c | 3 ++- - fs/fat/fat.c | 1 + - lib/efi_loader/efi_memory.c | 1 + - lib/fdtdec.c | 3 ++- - 4 files changed, 6 insertions(+), 2 deletions(-) - --- -2.7.4 - diff --git a/tools/patman/test/0001-pci-Correct-cast-for-sandbox.patch b/tools/patman/test/0001-pci-Correct-cast-for-sandbox.patch deleted file mode 100644 index 038943c2c9b..00000000000 --- a/tools/patman/test/0001-pci-Correct-cast-for-sandbox.patch +++ /dev/null @@ -1,51 +0,0 @@ -From b9da5f937bd5ea4931ea17459bf79b2905d9594d Mon Sep 17 00:00:00 2001 -From: Simon Glass <[email protected]> -Date: Sat, 15 Apr 2017 15:39:08 -0600 -Subject: [RFC 1/2] pci: Correct cast for sandbox -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This gives a warning with some native compilers: - -cmd/pci.c:152:11: warning: format ‘%llx’ expects argument of type - ‘long long unsigned int’, but argument 3 has type - ‘u64 {aka long unsigned int}’ [-Wformat=] - -Fix it with a cast. - -Signed-off-by: Simon Glass <[email protected]> -Commit-changes: 2 -- Changes only for this commit - -Series-notes: -some notes -about some things -from the first commit -END - -Commit-notes: -Some notes about -the first commit -END ---- - cmd/pci.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/cmd/pci.c b/cmd/pci.c -index 41b4fff..fe27b4f 100644 ---- a/cmd/pci.c -+++ b/cmd/pci.c -@@ -150,7 +150,8 @@ int pci_bar_show(struct udevice *dev) - if ((!is_64 && size_low) || (is_64 && size)) { - size = ~size + 1; - printf(" %d %#016llx %#016llx %d %s %s\n", -- bar_id, base, size, is_64 ? 64 : 32, -+ bar_id, (unsigned long long)base, -+ (unsigned long long)size, is_64 ? 64 : 32, - is_io ? "I/O" : "MEM", - prefetchable ? "Prefetchable" : ""); - } --- -2.7.4 - diff --git a/tools/patman/test/0002-fdt-Correct-cast-for-sandbox-in-fdtdec_setup_mem_siz.patch b/tools/patman/test/0002-fdt-Correct-cast-for-sandbox-in-fdtdec_setup_mem_siz.patch deleted file mode 100644 index 48ea1793b47..00000000000 --- a/tools/patman/test/0002-fdt-Correct-cast-for-sandbox-in-fdtdec_setup_mem_siz.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 5ab48490f03051875ab13d288a4bf32b507d76fd Mon Sep 17 00:00:00 2001 -From: Simon Glass <[email protected]> -Date: Sat, 15 Apr 2017 15:39:08 -0600 -Subject: [RFC 2/2] fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This gives a warning with some native compilers: - -lib/fdtdec.c:1203:8: warning: format ‘%llx’ expects argument of type - ‘long long unsigned int’, but argument 3 has type - ‘long unsigned int’ [-Wformat=] - -Fix it with a cast. - -Signed-off-by: Simon Glass <[email protected]> -Series-to: u-boot -Series-prefix: RFC -Series-cc: Stefan Brüns <[email protected]> -Cover-letter-cc: Lord Mëlchett <[email protected]> -Series-version: 3 -Patch-cc: fred -Commit-cc: joe -Series-process-log: sort, uniq -Commit-added-in: 4 -Series-changes: 4 -- Some changes -- Multi - line - change - -Commit-changes: 2 -- Changes only for this commit - -Cover-changes: 4 -- Some notes for the cover letter - -Cover-letter: -test: A test patch series -This is a test of how the cover -letter -works -END ---- - fs/fat/fat.c | 1 + - lib/efi_loader/efi_memory.c | 1 + - lib/fdtdec.c | 3 ++- - 3 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/fs/fat/fat.c b/fs/fat/fat.c -index a71bad1..ba169dc 100644 ---- a/fs/fat/fat.c -+++ b/fs/fat/fat.c -@@ -1,3 +1,4 @@ -+ - /* - * fat.c - * -diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c -index db2ae19..05f75d1 100644 ---- a/lib/efi_loader/efi_memory.c -+++ b/lib/efi_loader/efi_memory.c -@@ -1,3 +1,4 @@ -+ - /* - * EFI application memory management - * -diff --git a/lib/fdtdec.c b/lib/fdtdec.c -index c072e54..942244f 100644 ---- a/lib/fdtdec.c -+++ b/lib/fdtdec.c -@@ -1200,7 +1200,8 @@ int fdtdec_setup_mem_size_base(void) - } - - gd->ram_size = (phys_size_t)(res.end - res.start + 1); -- debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size); -+ debug("%s: Initial DRAM size %llx\n", __func__, -+ (unsigned long long)gd->ram_size); - - return 0; - } --- -2.7.4 - diff --git a/tools/patman/test/test01.txt b/tools/patman/test/test01.txt deleted file mode 100644 index b2d73c5972c..00000000000 --- a/tools/patman/test/test01.txt +++ /dev/null @@ -1,72 +0,0 @@ -commit b9da5f937bd5ea4931ea17459bf79b2905d9594d -Author: Simon Glass <[email protected]> -Date: Sat Apr 15 15:39:08 2017 -0600 - - pci: Correct cast for sandbox - - This gives a warning with some native compilers: - - cmd/pci.c:152:11: warning: format ‘%llx’ expects argument of type - ‘long long unsigned int’, but argument 3 has type - ‘u64 {aka long unsigned int}’ [-Wformat=] - - Fix it with a cast. - - Signed-off-by: Simon Glass <[email protected]> - Commit-changes: 2 - - second revision change - - Series-notes: - some notes - about some things - from the first commit - END - - Commit-notes: - Some notes about - the first commit - END - -commit 5ab48490f03051875ab13d288a4bf32b507d76fd -Author: Simon Glass <[email protected]> -Date: Sat Apr 15 15:39:08 2017 -0600 - - fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base() - - This gives a warning with some native compilers: - - lib/fdtdec.c:1203:8: warning: format ‘%llx’ expects argument of type - ‘long long unsigned int’, but argument 3 has type - ‘long unsigned int’ [-Wformat=] - - Fix it with a cast. - - Signed-off-by: Simon Glass <[email protected]> - Series-to: u-boot - Series-prefix: RFC - Series-postfix: some-branch - Series-cc: Stefan Brüns <[email protected]> - Cover-letter-cc: Lord Mëlchett <[email protected]> - Series-version: 3 - Patch-cc: fred - Commit-cc: joe - Series-process-log: sort, uniq - Commit-added-in: 4 - Series-changes: 4 - - Some changes - - Multi - line - change - - Commit-changes: 2 - - Changes only for this commit - - Cover-changes: 4 - - Some notes for the cover letter - - Cover-letter: - test: A test patch series - This is a test of how the cover - letter - works - END diff --git a/tools/patman/test_checkpatch.py b/tools/patman/test_checkpatch.py deleted file mode 100644 index b4722330f86..00000000000 --- a/tools/patman/test_checkpatch.py +++ /dev/null @@ -1,526 +0,0 @@ -# -*- coding: utf-8 -*- -# SPDX-License-Identifier: GPL-2.0+ -# -# Tests for U-Boot-specific checkpatch.pl features -# -# Copyright (c) 2011 The Chromium OS Authors. -# - -import os -import tempfile -import unittest - -from patman import checkpatch -from patman import patchstream -from patman import series -from patman import commit -from u_boot_pylib import gitutil - - -class Line: - """Single changed line in one file in a patch - - Args: - fname (str): Filename containing the added line - text (str): Text of the added line - """ - def __init__(self, fname, text): - self.fname = fname - self.text = text - - -class PatchMaker: - """Makes a patch for checking with checkpatch.pl - - The idea here is to create a patch which adds one line in one file, - intended to provoke a checkpatch error or warning. The base patch is empty - (i.e. invalid), so you should call add_line() to add at least one line. - """ - def __init__(self): - """Set up the PatchMaker object - - Properties: - lines (list of Line): List of lines to add to the patch. Note that - each line has both a file and some text associated with it, - since for simplicity we just add a single line for each file - """ - self.lines = [] - - def add_line(self, fname, text): - """Add to the list of filename/line pairs""" - self.lines.append(Line(fname, text)) - - def get_patch_text(self): - """Build the patch text - - Takes a base patch and adds a diffstat and patch for each filename/line - pair in the list. - - Returns: - str: Patch text ready for submission to checkpatch - """ - base = '''From 125b77450f4c66b8fd9654319520bbe795c9ef31 Mon Sep 17 00:00:00 2001 -From: Simon Glass <[email protected]> -Date: Sun, 14 Jun 2020 09:45:14 -0600 -Subject: [PATCH] Test commit - -This is a test commit. - -Signed-off-by: Simon Glass <[email protected]> ---- - -''' - lines = base.splitlines() - - # Create the diffstat - change = 0 - insert = 0 - for line in self.lines: - lines.append(' %s | 1 +' % line.fname) - change += 1 - insert += 1 - lines.append(' %d files changed, %d insertions(+)' % (change, insert)) - lines.append('') - - # Create the patch info for each file - for line in self.lines: - lines.append('diff --git a/%s b/%s' % (line.fname, line.fname)) - lines.append('index 7837d459f18..5ba7840f68e 100644') - lines.append('--- a/%s' % line.fname) - lines.append('+++ b/%s' % line.fname) - lines += ('''@@ -121,6 +121,7 @@ enum uclass_id { - UCLASS_W1, /* Dallas 1-Wire bus */ - UCLASS_W1_EEPROM, /* one-wire EEPROMs */ - UCLASS_WDT, /* Watchdog Timer driver */ -+%s - - UCLASS_COUNT, - UCLASS_INVALID = -1, -''' % line.text).splitlines() - lines.append('---') - lines.append('2.17.1') - - return '\n'.join(lines) - - def get_patch(self): - """Get the patch text and write it into a temporary file - - Returns: - str: Filename containing the patch - """ - inhandle, inname = tempfile.mkstemp() - infd = os.fdopen(inhandle, 'w') - infd.write(self.get_patch_text()) - infd.close() - return inname - - def run_checkpatch(self): - """Run checkpatch on the patch file - - Returns: - namedtuple containing: - ok: False=failure, True=ok - problems: List of problems, each a dict: - 'type'; error or warning - 'msg': text message - 'file' : filename - 'line': line number - errors: Number of errors - warnings: Number of warnings - checks: Number of checks - lines: Number of lines - stdout: Full output of checkpatch - """ - return checkpatch.check_patch(self.get_patch(), show_types=True) - - -class TestPatch(unittest.TestCase): - """Test the u_boot_line() function in checkpatch.pl""" - - def test_filter(self): - """Test basic filter operation""" - data=''' - -From 656c9a8c31fa65859d924cd21da920d6ba537fad Mon Sep 17 00:00:00 2001 -From: Simon Glass <[email protected]> -Date: Thu, 28 Apr 2011 09:58:51 -0700 -Subject: [PATCH (resend) 3/7] Tegra2: Add more clock support - -This adds functions to enable/disable clocks and reset to on-chip peripherals. - -cmd/pci.c:152:11: warning: format ‘%llx’ expects argument of type - ‘long long unsigned int’, but argument 3 has type - ‘u64 {aka long unsigned int}’ [-Wformat=] - -BUG=chromium-os:13875 -TEST=build U-Boot for Seaboard, boot - -Change-Id: I80fe1d0c0b7dd10aa58ce5bb1d9290b6664d5413 - -Review URL: http://codereview.chromium.org/6900006 - -Signed-off-by: Simon Glass <[email protected]> ---- - arch/arm/cpu/armv7/tegra2/Makefile | 2 +- - arch/arm/cpu/armv7/tegra2/ap20.c | 57 ++---- - arch/arm/cpu/armv7/tegra2/clock.c | 163 +++++++++++++++++ -''' - expected='''Message-Id: <19991231235959.0.I80fe1d0c0b7dd10aa58ce5bb1d9290b6664d5413@changeid> - - -From 656c9a8c31fa65859d924cd21da920d6ba537fad Mon Sep 17 00:00:00 2001 -From: Simon Glass <[email protected]> -Date: Thu, 28 Apr 2011 09:58:51 -0700 -Subject: [PATCH (resend) 3/7] Tegra2: Add more clock support - -This adds functions to enable/disable clocks and reset to on-chip peripherals. - -cmd/pci.c:152:11: warning: format ‘%llx’ expects argument of type - ‘long long unsigned int’, but argument 3 has type - ‘u64 {aka long unsigned int}’ [-Wformat=] - -Signed-off-by: Simon Glass <[email protected]> ---- - - arch/arm/cpu/armv7/tegra2/Makefile | 2 +- - arch/arm/cpu/armv7/tegra2/ap20.c | 57 ++---- - arch/arm/cpu/armv7/tegra2/clock.c | 163 +++++++++++++++++ -''' - out = '' - inhandle, inname = tempfile.mkstemp() - infd = os.fdopen(inhandle, 'w', encoding='utf-8') - infd.write(data) - infd.close() - - exphandle, expname = tempfile.mkstemp() - expfd = os.fdopen(exphandle, 'w', encoding='utf-8') - expfd.write(expected) - expfd.close() - - # Normally by the time we call fix_patch we've already collected - # metadata. Here, we haven't, but at least fake up something. - # Set the "count" to -1 which tells fix_patch to use a bogus/fixed - # time for generating the Message-Id. - com = commit.Commit('') - com.change_id = 'I80fe1d0c0b7dd10aa58ce5bb1d9290b6664d5413' - com.count = -1 - - patchstream.fix_patch(None, inname, series.Series(), com) - - rc = os.system('diff -u %s %s' % (inname, expname)) - self.assertEqual(rc, 0) - os.remove(inname) - - # Test whether the keep_change_id settings works. - inhandle, inname = tempfile.mkstemp() - infd = os.fdopen(inhandle, 'w', encoding='utf-8') - infd.write(data) - infd.close() - - patchstream.fix_patch(None, inname, series.Series(), com, - keep_change_id=True) - - with open(inname, 'r') as f: - content = f.read() - self.assertIn( - 'Change-Id: I80fe1d0c0b7dd10aa58ce5bb1d9290b6664d5413', - content) - - os.remove(inname) - os.remove(expname) - - def get_data(self, data_type): - data='''From 4924887af52713cabea78420eff03badea8f0035 Mon Sep 17 00:00:00 2001 -From: Simon Glass <[email protected]> -Date: Thu, 7 Apr 2011 10:14:41 -0700 -Subject: [PATCH 1/4] Add microsecond boot time measurement - -This defines the basics of a new boot time measurement feature. This allows -logging of very accurate time measurements as the boot proceeds, by using -an available microsecond counter. - -%s ---- - README | 11 ++++++++ - MAINTAINERS | 3 ++ - common/bootstage.c | 50 ++++++++++++++++++++++++++++++++++++ - include/bootstage.h | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++ - include/common.h | 8 ++++++ - 5 files changed, 141 insertions(+), 0 deletions(-) - create mode 100644 common/bootstage.c - create mode 100644 include/bootstage.h - -diff --git a/README b/README -index 6f3748d..f9e4e65 100644 ---- a/README -+++ b/README -@@ -2026,6 +2026,17 @@ The following options need to be configured: - example, some LED's) on your board. At the moment, - the following checkpoints are implemented: - -+- Time boot progress -+ CONFIG_BOOTSTAGE -+ -+ Define this option to enable microsecond boot stage timing -+ on supported platforms. For this to work your platform -+ needs to define a function timer_get_us() which returns the -+ number of microseconds since reset. This would normally -+ be done in your SOC or board timer.c file. -+ -+ You can add calls to bootstage_mark() to set time markers. -+ - - Standalone program support: - CONFIG_STANDALONE_LOAD_ADDR - -diff --git a/MAINTAINERS b/MAINTAINERS -index b167b028ec..beb7dc634f 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -474,3 +474,8 @@ S: Maintained - T: git git://git.denx.de/u-boot.git - F: * - F: */ -+ -+BOOTSTAGE -+M: Simon Glass <[email protected]> -+L: [email protected] -+F: common/bootstage.c -diff --git a/common/bootstage.c b/common/bootstage.c -new file mode 100644 -index 0000000..2234c87 ---- /dev/null -+++ b/common/bootstage.c -@@ -0,0 +1,37 @@ -+%s -+/* -+ * Copyright (c) 2011, Google Inc. All rights reserved. -+ * -+ */ -+ -+/* -+ * This module records the progress of boot and arbitrary commands, and -+ * permits accurate timestamping of each. The records can optionally be -+ * passed to kernel in the ATAGs -+ */ -+ -+#include <config.h> -+ -+struct bootstage_record { -+ u32 time_us; -+ const char *name; -+}; -+ -+static struct bootstage_record record[BOOTSTAGE_COUNT]; -+ -+u32 bootstage_mark(enum bootstage_id id, const char *name) -+{ -+ struct bootstage_record *rec = &record[id]; -+ -+ /* Only record the first event for each */ -+%sif (!rec->name) { -+ rec->time_us = (u32)timer_get_us(); -+ rec->name = name; -+ } -+ if (!rec->name && -+ %ssomething_else) { -+ rec->time_us = (u32)timer_get_us(); -+ rec->name = name; -+ } -+%sreturn rec->time_us; -+} --- -1.7.3.1 -''' - signoff = 'Signed-off-by: Simon Glass <[email protected]>\n' - license = '// SPDX-License-Identifier: GPL-2.0+' - tab = ' ' - indent = ' ' - if data_type == 'good': - pass - elif data_type == 'no-signoff': - signoff = '' - elif data_type == 'no-license': - license = '' - elif data_type == 'spaces': - tab = ' ' - elif data_type == 'indent': - indent = tab - else: - print('not implemented') - return data % (signoff, license, tab, indent, tab) - - def setup_data(self, data_type): - inhandle, inname = tempfile.mkstemp() - infd = os.fdopen(inhandle, 'w') - data = self.get_data(data_type) - infd.write(data) - infd.close() - return inname - - def test_good(self): - """Test checkpatch operation""" - inf = self.setup_data('good') - result = checkpatch.check_patch(inf) - self.assertEqual(result.ok, True) - self.assertEqual(result.problems, []) - self.assertEqual(result.errors, 0) - self.assertEqual(result.warnings, 0) - self.assertEqual(result.checks, 0) - self.assertEqual(result.lines, 62) - os.remove(inf) - - def test_no_signoff(self): - inf = self.setup_data('no-signoff') - result = checkpatch.check_patch(inf) - self.assertEqual(result.ok, False) - self.assertEqual(len(result.problems), 1) - self.assertEqual(result.errors, 1) - self.assertEqual(result.warnings, 0) - self.assertEqual(result.checks, 0) - self.assertEqual(result.lines, 62) - os.remove(inf) - - def test_no_license(self): - inf = self.setup_data('no-license') - result = checkpatch.check_patch(inf) - self.assertEqual(result.ok, False) - self.assertEqual(len(result.problems), 1) - self.assertEqual(result.errors, 0) - self.assertEqual(result.warnings, 1) - self.assertEqual(result.checks, 0) - self.assertEqual(result.lines, 62) - os.remove(inf) - - def test_spaces(self): - inf = self.setup_data('spaces') - result = checkpatch.check_patch(inf) - self.assertEqual(result.ok, False) - self.assertEqual(len(result.problems), 3) - self.assertEqual(result.errors, 0) - self.assertEqual(result.warnings, 3) - self.assertEqual(result.checks, 0) - self.assertEqual(result.lines, 62) - os.remove(inf) - - def test_indent(self): - inf = self.setup_data('indent') - result = checkpatch.check_patch(inf) - self.assertEqual(result.ok, False) - self.assertEqual(len(result.problems), 1) - self.assertEqual(result.errors, 0) - self.assertEqual(result.warnings, 0) - self.assertEqual(result.checks, 1) - self.assertEqual(result.lines, 62) - os.remove(inf) - - def check_single_message(self, pm, msg, pmtype = 'warning'): - """Helper function to run checkpatch and check the result - - Args: - pm: PatchMaker object to use - msg: Expected message (e.g. 'LIVETREE') - pmtype: Type of problem ('error', 'warning') - """ - result = pm.run_checkpatch() - if pmtype == 'warning': - self.assertEqual(result.warnings, 1) - elif pmtype == 'error': - self.assertEqual(result.errors, 1) - if len(result.problems) != 1: - print(result.problems) - self.assertEqual(len(result.problems), 1) - self.assertIn(msg, result.problems[0]['cptype']) - - def test_uclass(self): - """Test for possible new uclass""" - pm = PatchMaker() - pm.add_line('include/dm/uclass-id.h', 'UCLASS_WIBBLE,') - self.check_single_message(pm, 'NEW_UCLASS') - - def test_livetree(self): - """Test for using the livetree API""" - pm = PatchMaker() - pm.add_line('common/main.c', 'fdtdec_do_something()') - self.check_single_message(pm, 'LIVETREE') - - def test_new_command(self): - """Test for adding a new command""" - pm = PatchMaker() - pm.add_line('common/main.c', 'do_wibble(struct cmd_tbl *cmd_tbl)') - self.check_single_message(pm, 'CMD_TEST') - - def test_prefer_if(self): - """Test for using #ifdef""" - pm = PatchMaker() - pm.add_line('common/main.c', '#ifdef CONFIG_YELLOW') - pm.add_line('common/init.h', '#ifdef CONFIG_YELLOW') - pm.add_line('fred.dtsi', '#ifdef CONFIG_YELLOW') - self.check_single_message(pm, "PREFER_IF") - - def test_command_use_defconfig(self): - """Test for enabling/disabling commands using preprocesor""" - pm = PatchMaker() - pm.add_line('common/main.c', '#undef CONFIG_CMD_WHICH') - self.check_single_message(pm, 'DEFINE_CONFIG_SYM', 'error') - - def test_barred_include_in_hdr(self): - """Test for using a barred include in a header file""" - pm = PatchMaker() - pm.add_line('include/myfile.h', '#include <dm.h>') - self.check_single_message(pm, 'BARRED_INCLUDE_IN_HDR', 'error') - - def test_barred_include_common_h(self): - """Test for adding common.h to a file""" - pm = PatchMaker() - pm.add_line('include/myfile.h', '#include <common.h>') - self.check_single_message(pm, 'BARRED_INCLUDE_COMMON_H', 'error') - - def test_config_is_enabled_config(self): - """Test for accidental CONFIG_IS_ENABLED(CONFIG_*) calls""" - pm = PatchMaker() - pm.add_line('common/main.c', 'if (CONFIG_IS_ENABLED(CONFIG_CLK))') - self.check_single_message(pm, 'CONFIG_IS_ENABLED_CONFIG', 'error') - - def check_struct(self, auto, suffix, warning): - """Check one of the warnings for struct naming - - Args: - auto: Auto variable name, e.g. 'per_child_auto' - suffix: Suffix to expect on member, e.g. '_priv' - warning: Warning name, e.g. 'PRIV_AUTO' - """ - pm = PatchMaker() - pm.add_line('common/main.c', '.%s = sizeof(struct(fred)),' % auto) - pm.add_line('common/main.c', '.%s = sizeof(struct(mary%s)),' % - (auto, suffix)) - self.check_single_message( - pm, warning, "struct 'fred' should have a %s suffix" % suffix) - - def test_dm_driver_auto(self): - """Check for the correct suffix on 'struct driver' auto members""" - self.check_struct('priv_auto', '_priv', 'PRIV_AUTO') - self.check_struct('plat_auto', '_plat', 'PLAT_AUTO') - self.check_struct('per_child_auto', '_priv', 'CHILD_PRIV_AUTO') - self.check_struct('per_child_plat_auto', '_plat', 'CHILD_PLAT_AUTO') - - def test_dm_uclass_auto(self): - """Check for the correct suffix on 'struct uclass' auto members""" - # Some of these are omitted since they match those from struct driver - self.check_struct('per_device_auto', '_priv', 'DEVICE_PRIV_AUTO') - self.check_struct('per_device_plat_auto', '_plat', 'DEVICE_PLAT_AUTO') - - def check_strl(self, func): - """Check one of the checks for strn(cpy|cat)""" - pm = PatchMaker() - pm.add_line('common/main.c', "strn%s(foo, bar, sizeof(foo));" % func) - self.check_single_message(pm, "STRL", - "strl%s is preferred over strn%s because it always produces a nul-terminated string\n" - % (func, func)) - - def test_strl(self): - """Check for uses of strn(cat|cpy)""" - self.check_strl("cat"); - self.check_strl("cpy"); - -if __name__ == "__main__": - unittest.main() diff --git a/tools/patman/test_common.py b/tools/patman/test_common.py deleted file mode 100644 index 7da995dda22..00000000000 --- a/tools/patman/test_common.py +++ /dev/null @@ -1,254 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0+ -# -# Copyright 2025 Simon Glass <[email protected]> -# -"""Functional tests for checking that patman behaves correctly""" - -import os -import shutil -import tempfile - -import pygit2 - -from u_boot_pylib import gitutil -from u_boot_pylib import terminal -from u_boot_pylib import tools -from u_boot_pylib import tout - - -class TestCommon: - """Contains common test functions""" - leb = (b'Lord Edmund Blackadd\xc3\xabr <[email protected]>'. - decode('utf-8')) - - # Fake patchwork project ID for U-Boot - PROJ_ID = 6 - PROJ_LINK_NAME = 'uboot' - SERIES_ID_FIRST_V3 = 31 - SERIES_ID_SECOND_V1 = 456 - SERIES_ID_SECOND_V2 = 457 - TITLE_SECOND = 'Series for my board' - - verbosity = False - preserve_outdirs = False - - @classmethod - def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False, - toolpath=None, verbosity=None, no_capture=False): - """Accept arguments controlling test execution - - Args: - preserve_indir (bool): not used by patman - preserve_outdirs (bool): Preserve the output directories used by - tests. Each test has its own, so this is normally only useful - when running a single test. - toolpath (str): not used by patman - verbosity (int): verbosity to use (0 means tout.INIT, 1 means means - tout.DEBUG) - no_capture (bool): True to output all captured text after capturing - completes - """ - del preserve_indir - cls.preserve_outdirs = preserve_outdirs - cls.toolpath = toolpath - cls.verbosity = verbosity - cls.no_capture = no_capture - - def __init__(self): - super().__init__() - self.repo = None - self.tmpdir = None - self.gitdir = None - - def setUp(self): - """Set up the test temporary dir and git dir""" - self.tmpdir = tempfile.mkdtemp(prefix='patman.') - self.gitdir = os.path.join(self.tmpdir, '.git') - tout.init(tout.DEBUG if self.verbosity else tout.INFO, - allow_colour=False) - - def tearDown(self): - """Delete the temporary dir""" - if self.preserve_outdirs: - print(f'Output dir: {self.tmpdir}') - else: - shutil.rmtree(self.tmpdir) - terminal.set_print_test_mode(False) - - def make_commit_with_file(self, subject, body, fname, text): - """Create a file and add it to the git repo with a new commit - - Args: - subject (str): Subject for the commit - body (str): Body text of the commit - fname (str): Filename of file to create - text (str): Text to put into the file - """ - path = os.path.join(self.tmpdir, fname) - tools.write_file(path, text, binary=False) - index = self.repo.index - index.add(fname) - # pylint doesn't seem to find this - # pylint: disable=E1101 - author = pygit2.Signature('Test user', '[email protected]') - committer = author - tree = index.write_tree() - message = subject + '\n' + body - self.repo.create_commit('HEAD', author, committer, message, tree, - [self.repo.head.target]) - - def make_git_tree(self): - """Make a simple git tree suitable for testing - - It has four branches: - 'base' has two commits: PCI, main - 'first' has base as upstream and two more commits: I2C, SPI - 'second' has base as upstream and three more: video, serial, bootm - 'third4' has second as upstream and four more: usb, main, test, lib - - Returns: - pygit2.Repository: repository - """ - os.environ['GIT_CONFIG_GLOBAL'] = '/dev/null' - os.environ['GIT_CONFIG_SYSTEM'] = '/dev/null' - - repo = pygit2.init_repository(self.gitdir) - self.repo = repo - new_tree = repo.TreeBuilder().write() - - common = ['git', f'--git-dir={self.gitdir}', 'config'] - tools.run(*(common + ['user.name', 'Dummy']), cwd=self.gitdir) - tools.run(*(common + ['user.email', '[email protected]']), - cwd=self.gitdir) - - # pylint doesn't seem to find this - # pylint: disable=E1101 - author = pygit2.Signature('Test user', '[email protected]') - committer = author - _ = repo.create_commit('HEAD', author, committer, 'Created master', - new_tree, []) - - self.make_commit_with_file('Initial commit', ''' -Add a README - -''', 'README', '''This is the README file -describing this project -in very little detail''') - - self.make_commit_with_file('pci: PCI implementation', ''' -Here is a basic PCI implementation - -''', 'pci.c', '''This is a file -it has some contents -and some more things''') - self.make_commit_with_file('main: Main program', ''' -Hello here is the second commit. -''', 'main.c', '''This is the main file -there is very little here -but we can always add more later -if we want to - -Series-to: u-boot -Series-cc: Barry Crump <[email protected]> -''') - base_target = repo.revparse_single('HEAD') - self.make_commit_with_file('i2c: I2C things', ''' -This has some stuff to do with I2C -''', 'i2c.c', '''And this is the file contents -with some I2C-related things in it''') - self.make_commit_with_file('spi: SPI fixes', f''' -SPI needs some fixes -and here they are - -Signed-off-by: {self.leb} - -Series-to: u-boot -Commit-notes: -title of the series -This is the cover letter for the series -with various details -END -''', 'spi.c', '''Some fixes for SPI in this -file to make SPI work -better than before''') - first_target = repo.revparse_single('HEAD') - - target = repo.revparse_single('HEAD~2') - # pylint doesn't seem to find this - # pylint: disable=E1101 - repo.reset(target.oid, pygit2.enums.ResetMode.HARD) - self.make_commit_with_file('video: Some video improvements', ''' -Fix up the video so that -it looks more purple. Purple is -a very nice colour. -''', 'video.c', '''More purple here -Purple and purple -Even more purple -Could not be any more purple''') - self.make_commit_with_file('serial: Add a serial driver', f''' -Here is the serial driver -for my chip. - -Cover-letter: -{self.TITLE_SECOND} -This series implements support -for my glorious board. -END -Series-to: u-boot -Series-links: {self.SERIES_ID_SECOND_V1} -''', 'serial.c', '''The code for the -serial driver is here''') - self.make_commit_with_file('bootm: Make it boot', ''' -This makes my board boot -with a fix to the bootm -command -''', 'bootm.c', '''Fix up the bootm -command to make the code as -complicated as possible''') - second_target = repo.revparse_single('HEAD') - - self.make_commit_with_file('usb: Try out the new DMA feature', ''' -This is just a fix that -ensures that DMA is enabled -''', 'usb-uclass.c', '''Here is the USB -implementation and as you can see it -it very nice''') - self.make_commit_with_file('main: Change to the main program', ''' -Here we adjust the main -program just a little bit -''', 'main.c', '''This is the text of the main program''') - self.make_commit_with_file('test: Check that everything works', ''' -This checks that all the -various things we've been -adding actually work. -''', 'test.c', '''Here is the test code and it seems OK''') - self.make_commit_with_file('lib: Sort out the extra library', ''' -The extra library is currently -broken. Fix it so that we can -use it in various place. -''', 'lib.c', '''Some library code is here -and a little more''') - third_target = repo.revparse_single('HEAD') - - repo.branches.local.create('first', first_target) - repo.config.set_multivar('branch.first.remote', '', '.') - repo.config.set_multivar('branch.first.merge', '', 'refs/heads/base') - - repo.branches.local.create('second', second_target) - repo.config.set_multivar('branch.second.remote', '', '.') - repo.config.set_multivar('branch.second.merge', '', 'refs/heads/base') - - repo.branches.local.create('base', base_target) - - repo.branches.local.create('third4', third_target) - repo.config.set_multivar('branch.third4.remote', '', '.') - repo.config.set_multivar('branch.third4.merge', '', - 'refs/heads/second') - - target = repo.lookup_reference('refs/heads/first') - repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE) - target = repo.revparse_single('HEAD') - repo.reset(target.oid, pygit2.enums.ResetMode.HARD) - - self.assertFalse(gitutil.check_dirty(self.gitdir, self.tmpdir)) - return repo diff --git a/tools/patman/test_cseries.py b/tools/patman/test_cseries.py deleted file mode 100644 index 4c211c8ee89..00000000000 --- a/tools/patman/test_cseries.py +++ /dev/null @@ -1,3684 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0+ - -# Copyright 2025 Simon Glass <[email protected]> -# -"""Functional tests for checking that patman behaves correctly""" - -import asyncio -from datetime import datetime -import os -import re -import unittest -from unittest import mock - -import pygit2 - -from u_boot_pylib import cros_subprocess -from u_boot_pylib import gitutil -from u_boot_pylib import terminal -from u_boot_pylib import tools -from patman import cmdline -from patman import control -from patman import cser_helper -from patman import cseries -from patman.database import Pcommit -from patman import database -from patman import patchstream -from patman.patchwork import Patchwork -from patman.test_common import TestCommon - -HASH_RE = r'[0-9a-f]+' -#pylint: disable=protected-access - -class Namespace: - """Simple namespace for use instead of argparse in tests""" - def __init__(self, **kwargs): - self.__dict__.update(kwargs) - - -class TestCseries(unittest.TestCase, TestCommon): - """Test cases for the Cseries class - - In some cases there are tests for both direct Cseries calls and for - accessing the feature via the cmdline. It is possible to do this with mocks - but it is a bit painful to catch all cases that way. The approach here is - to create a check_...() function which yields back to the test routines to - make the call or run the command. The check_...() function typically yields - a Cseries while it is working and False when it is done, allowing the test - to check that everything is finished. - - Some subcommands don't have command tests, if it would be duplicative. Some - tests avoid using the check_...() function and just write the test out - twice, if it would be too confusing to use a coroutine. - - Note the -N flag which sort-of disables capturing of output, although in - fact it is still captured, just output at the end. When debugging the code - you may need to temporarily comment out the 'with terminal.capture()' - parts. - """ - def setUp(self): - TestCommon.setUp(self) - self.autolink_extra = None - self.loop = asyncio.get_event_loop() - self.cser = None - - def tearDown(self): - TestCommon.tearDown(self) - - class _Stage: - def __init__(self, name): - self.name = name - - def __enter__(self): - if not terminal.USE_CAPTURE: - print(f"--- starting '{self.name}'") - - def __exit__(self, exc_type, exc_val, exc_tb): - if not terminal.USE_CAPTURE: - print(f"--- finished '{self.name}'\n") - - def stage(self, name): - """Context manager to count requests across a range of patchwork calls - - Args: - name (str): Stage name - - Return: - _Stage: contect object - - Usage: - with self.stage('name'): - ...do things - - Note that the output only appears if the -N flag is used - """ - return self._Stage(name) - - def assert_finished(self, itr): - """Assert that an iterator is finished - - Args: - itr (iter): Iterator to check - """ - self.assertFalse(list(itr)) - - def test_database_setup(self): - """Check setting up of the series database""" - cser = cseries.Cseries(self.tmpdir) - with terminal.capture() as (_, err): - cser.open_database() - self.assertEqual(f'Creating new database {self.tmpdir}/.patman.db', - err.getvalue().strip()) - res = cser.db.execute("SELECT name FROM series") - self.assertTrue(res) - cser.close_database() - - def get_database(self): - """Open the database and silence the warning output - - Return: - Cseries: Resulting Cseries object - """ - cser = cseries.Cseries(self.tmpdir, terminal.COLOR_NEVER) - with terminal.capture() as _: - cser.open_database() - self.cser = cser - return cser - - def get_cser(self): - """Set up a git tree and database - - Return: - Cseries: object - """ - self.make_git_tree() - return self.get_database() - - def db_close(self): - """Close the database if open""" - if self.cser and self.cser.db.cur: - self.cser.close_database() - return True - return False - - def db_open(self): - """Open the database if closed""" - if self.cser and not self.cser.db.cur: - self.cser.open_database() - - def run_args(self, *argv, expect_ret=0, pwork=None, cser=None): - """Run patman with the given arguments - - Args: - argv (list of str): List of arguments, excluding 'patman' - expect_ret (int): Expected return code, used to check errors - pwork (Patchwork): Patchwork object to use when executing the - command, or None to create one - cser (Cseries): Cseries object to use when executing the command, - or None to create one - """ - was_open = self.db_close() - args = cmdline.parse_args(['-D'] + list(argv), config_fname=False) - exit_code = control.do_patman(args, self.tmpdir, pwork, cser) - self.assertEqual(expect_ret, exit_code) - if was_open: - self.db_open() - - def test_series_add(self): - """Test adding a new cseries""" - cser = self.get_cser() - self.assertFalse(cser.db.series_get_dict()) - - with terminal.capture() as (out, _): - cser.add('first', 'my description', allow_unmarked=True) - lines = out.getvalue().strip().splitlines() - self.assertEqual( - "Adding series 'first' v1: mark False allow_unmarked True", - lines[0]) - self.assertEqual("Added series 'first' v1 (2 commits)", lines[1]) - self.assertEqual(2, len(lines)) - - slist = cser.db.series_get_dict() - self.assertEqual(1, len(slist)) - self.assertEqual('first', slist['first'].name) - self.assertEqual('my description', slist['first'].desc) - - svlist = cser.get_ser_ver_list() - self.assertEqual(1, len(svlist)) - self.assertEqual(1, svlist[0].idnum) - self.assertEqual(1, svlist[0].series_id) - self.assertEqual(1, svlist[0].version) - - pclist = cser.get_pcommit_dict() - self.assertEqual(2, len(pclist)) - self.assertIn(1, pclist) - self.assertEqual( - Pcommit(1, 0, 'i2c: I2C things', 1, None, None, None, None), - pclist[1]) - self.assertEqual( - Pcommit(2, 1, 'spi: SPI fixes', 1, None, None, None, None), - pclist[2]) - - def test_series_not_checked_out(self): - """Test adding a new cseries when a different one is checked out""" - cser = self.get_cser() - self.assertFalse(cser.db.series_get_dict()) - - with terminal.capture() as (out, _): - cser.add('second', allow_unmarked=True) - lines = out.getvalue().strip().splitlines() - self.assertEqual( - "Adding series 'second' v1: mark False allow_unmarked True", - lines[0]) - self.assertEqual("Added series 'second' v1 (3 commits)", lines[1]) - self.assertEqual(2, len(lines)) - - def test_series_add_manual(self): - """Test adding a new cseries with a version number""" - cser = self.get_cser() - self.assertFalse(cser.db.series_get_dict()) - - repo = pygit2.init_repository(self.gitdir) - first_target = repo.revparse_single('first') - repo.branches.local.create('first2', first_target) - repo.config.set_multivar('branch.first2.remote', '', '.') - repo.config.set_multivar('branch.first2.merge', '', 'refs/heads/base') - - with terminal.capture() as (out, _): - cser.add('first2', 'description', allow_unmarked=True) - lines = out.getvalue().splitlines() - self.assertEqual( - "Adding series 'first' v2: mark False allow_unmarked True", - lines[0]) - self.assertEqual("Added series 'first' v2 (2 commits)", lines[1]) - self.assertEqual(2, len(lines)) - - slist = cser.db.series_get_dict() - self.assertEqual(1, len(slist)) - self.assertEqual('first', slist['first'].name) - - # We should have just one entry, with version 2 - svlist = cser.get_ser_ver_list() - self.assertEqual(1, len(svlist)) - self.assertEqual(1, svlist[0].idnum) - self.assertEqual(1, svlist[0].series_id) - self.assertEqual(2, svlist[0].version) - - def add_first2(self, checkout): - """Add a new first2 branch, a copy of first""" - repo = pygit2.init_repository(self.gitdir) - first_target = repo.revparse_single('first') - repo.branches.local.create('first2', first_target) - repo.config.set_multivar('branch.first2.remote', '', '.') - repo.config.set_multivar('branch.first2.merge', '', 'refs/heads/base') - - if checkout: - target = repo.lookup_reference('refs/heads/first2') - repo.checkout(target, strategy=pygit2.enums.CheckoutStrategy.FORCE) - - def test_series_add_different(self): - """Test adding a different version of a series from that checked out""" - cser = self.get_cser() - - self.add_first2(True) - - # Add first2 initially - with terminal.capture() as (out, _): - cser.add(None, 'description', allow_unmarked=True) - lines = out.getvalue().splitlines() - self.assertEqual( - "Adding series 'first' v2: mark False allow_unmarked True", - lines[0]) - self.assertEqual("Added series 'first' v2 (2 commits)", lines[1]) - self.assertEqual(2, len(lines)) - - # Now add first: it should be added as a new version - with terminal.capture() as (out, _): - cser.add('first', 'description', allow_unmarked=True) - lines = out.getvalue().splitlines() - self.assertEqual( - "Adding series 'first' v1: mark False allow_unmarked True", - lines[0]) - self.assertEqual( - "Added v1 to existing series 'first' (2 commits)", lines[1]) - self.assertEqual(2, len(lines)) - - slist = cser.db.series_get_dict() - self.assertEqual(1, len(slist)) - self.assertEqual('first', slist['first'].name) - - # We should have two entries, one of each version - svlist = cser.get_ser_ver_list() - self.assertEqual(2, len(svlist)) - self.assertEqual(1, svlist[0].idnum) - self.assertEqual(1, svlist[0].series_id) - self.assertEqual(2, svlist[0].version) - - self.assertEqual(2, svlist[1].idnum) - self.assertEqual(1, svlist[1].series_id) - self.assertEqual(1, svlist[1].version) - - def test_series_add_dup(self): - """Test adding a series twice""" - cser = self.get_cser() - with terminal.capture() as (out, _): - cser.add(None, 'description', allow_unmarked=True) - - with terminal.capture() as (out, _): - cser.add(None, 'description', allow_unmarked=True) - self.assertIn("Series 'first' v1 already exists", - out.getvalue().strip()) - - self.add_first2(False) - - with terminal.capture() as (out, _): - cser.add('first2', 'description', allow_unmarked=True) - lines = out.getvalue().splitlines() - self.assertEqual( - "Added v2 to existing series 'first' (2 commits)", lines[1]) - - def test_series_add_dup_reverse(self): - """Test adding a series twice, v2 then v1""" - cser = self.get_cser() - self.add_first2(True) - with terminal.capture() as (out, _): - cser.add(None, 'description', allow_unmarked=True) - self.assertIn("Added series 'first' v2", out.getvalue().strip()) - - with terminal.capture() as (out, _): - cser.add('first', 'description', allow_unmarked=True) - self.assertIn("Added v1 to existing series 'first'", - out.getvalue().strip()) - - def test_series_add_dup_reverse_cmdline(self): - """Test adding a series twice, v2 then v1""" - cser = self.get_cser() - self.add_first2(True) - with terminal.capture() as (out, _): - self.run_args('series', 'add', '-M', '-D', 'description', - pwork=True) - self.assertIn("Added series 'first' v2 (2 commits)", - out.getvalue().strip()) - - with terminal.capture() as (out, _): - self.run_args('series', '-s', 'first', 'add', '-M', - '-D', 'description', pwork=True) - cser.add('first', 'description', allow_unmarked=True) - self.assertIn("Added v1 to existing series 'first'", - out.getvalue().strip()) - - def test_series_add_skip_version(self): - """Test adding a series which is v4 but has no earlier version""" - cser = self.get_cser() - with terminal.capture() as (out, _): - cser.add('third4', 'The glorious third series', mark=False, - allow_unmarked=True) - lines = out.getvalue().splitlines() - self.assertEqual( - "Adding series 'third' v4: mark False allow_unmarked True", - lines[0]) - self.assertEqual("Added series 'third' v4 (4 commits)", lines[1]) - self.assertEqual(2, len(lines)) - - sdict = cser.db.series_get_dict() - self.assertIn('third', sdict) - chk = sdict['third'] - self.assertEqual('third', chk['name']) - self.assertEqual('The glorious third series', chk['desc']) - - svid = cser.get_series_svid(chk['idnum'], 4) - self.assertEqual(4, len(cser.get_pcommit_dict(svid))) - - # Remove the series and add it again with just two commits - with terminal.capture(): - cser.remove('third4') - - with terminal.capture() as (out, _): - cser.add('third4', 'The glorious third series', mark=False, - allow_unmarked=True, end='third4~2') - lines = out.getvalue().splitlines() - self.assertEqual( - "Adding series 'third' v4: mark False allow_unmarked True", - lines[0]) - self.assertRegex( - lines[1], - 'Ending before .* main: Change to the main program') - self.assertEqual("Added series 'third' v4 (2 commits)", lines[2]) - - sdict = cser.db.series_get_dict() - self.assertIn('third', sdict) - chk = sdict['third'] - self.assertEqual('third', chk['name']) - self.assertEqual('The glorious third series', chk['desc']) - - svid = cser.get_series_svid(chk['idnum'], 4) - self.assertEqual(2, len(cser.get_pcommit_dict(svid))) - - def test_series_add_wrong_version(self): - """Test adding a series with an incorrect branch name or version - - This updates branch 'first' to have version 2, then tries to add it. - """ - cser = self.get_cser() - self.assertFalse(cser.db.series_get_dict()) - - with terminal.capture(): - _, ser, max_vers, _ = cser.prep_series('first') - cser.update_series('first', ser, max_vers, None, False, - add_vers=2) - - with self.assertRaises(ValueError) as exc: - with terminal.capture(): - cser.add('first', 'my description', allow_unmarked=True) - self.assertEqual( - "Series name 'first' suggests version 1 but Series-version tag " - 'indicates 2 (see --force-version)', str(exc.exception)) - - # Now try again with --force-version which should force version 1 - with terminal.capture() as (out, _): - cser.add('first', 'my description', allow_unmarked=True, - force_version=True) - itr = iter(out.getvalue().splitlines()) - self.assertEqual( - "Adding series 'first' v1: mark False allow_unmarked True", - next(itr)) - self.assertRegex( - next(itr), 'Checking out upstream commit refs/heads/base: .*') - self.assertEqual( - "Processing 2 commits from branch 'first'", next(itr)) - self.assertRegex(next(itr), - f'- {HASH_RE} as {HASH_RE} i2c: I2C things') - self.assertRegex(next(itr), - f'- rm v1: {HASH_RE} as {HASH_RE} spi: SPI fixes') - self.assertRegex(next(itr), - f'Updating branch first from {HASH_RE} to {HASH_RE}') - self.assertEqual("Added series 'first' v1 (2 commits)", next(itr)) - try: - self.assertEqual('extra line', next(itr)) - except StopIteration: - pass - - # Since this is v1 the Series-version tag should have been removed - series = patchstream.get_metadata('first', 0, 2, git_dir=self.gitdir) - self.assertNotIn('version', series) - - def _fake_patchwork_cser(self, subpath): - """Fake Patchwork server for the function below - - This handles accessing various things used by the tests below. It has - hard-coded data, about from self.autolink_extra which can be adjusted - by the test. - - Args: - subpath (str): URL subpath to use - """ - # Get a list of projects - if subpath == 'projects/': - return [ - {'id': self.PROJ_ID, 'name': 'U-Boot', - 'link_name': self.PROJ_LINK_NAME}, - {'id': 9, 'name': 'other', 'link_name': 'other'} - ] - - # Search for series by their cover-letter name - re_search = re.match(r'series/\?project=(\d+)&q=.*$', subpath) - if re_search: - result = [ - {'id': 56, 'name': 'contains first name', 'version': 1}, - {'id': 43, 'name': 'has first in it', 'version': 1}, - {'id': 1234, 'name': 'first series', 'version': 1}, - {'id': self.SERIES_ID_SECOND_V1, 'name': self.TITLE_SECOND, - 'version': 1}, - {'id': self.SERIES_ID_SECOND_V2, 'name': self.TITLE_SECOND, - 'version': 2}, - {'id': 12345, 'name': 'i2c: I2C things', 'version': 1}, - ] - if self.autolink_extra: - result += [self.autolink_extra] - return result - - # Read information about a series, given its link (patchwork series ID) - m_series = re.match(r'series/(\d+)/$', subpath) - series_id = int(m_series.group(1)) if m_series else '' - if series_id: - if series_id == self.SERIES_ID_SECOND_V1: - # series 'second' - return { - 'patches': [ - {'id': '10', - 'name': '[PATCH,1/3] video: Some video improvements', - 'content': ''}, - {'id': '11', - 'name': '[PATCH,2/3] serial: Add a serial driver', - 'content': ''}, - {'id': '12', 'name': '[PATCH,3/3] bootm: Make it boot', - 'content': ''}, - ], - 'cover_letter': { - 'id': 39, - 'name': 'The name of the cover letter', - } - } - if series_id == self.SERIES_ID_SECOND_V2: - # series 'second2' - return { - 'patches': [ - {'id': '110', - 'name': - '[PATCH,v2,1/3] video: Some video improvements', - 'content': ''}, - {'id': '111', - 'name': '[PATCH,v2,2/3] serial: Add a serial driver', - 'content': ''}, - {'id': '112', - 'name': '[PATCH,v2,3/3] bootm: Make it boot', - 'content': ''}, - ], - 'cover_letter': { - 'id': 139, - 'name': 'The name of the cover letter', - } - } - if series_id == self.SERIES_ID_FIRST_V3: - # series 'first3' - return { - 'patches': [ - {'id': 20, 'name': '[PATCH,v3,1/2] i2c: I2C things', - 'content': ''}, - {'id': 21, 'name': '[PATCH,v3,2/2] spi: SPI fixes', - 'content': ''}, - ], - 'cover_letter': { - 'id': 29, - 'name': 'Cover letter for first', - } - } - if series_id == 123: - return { - 'patches': [ - {'id': 20, 'name': '[PATCH,1/2] i2c: I2C things', - 'content': ''}, - {'id': 21, 'name': '[PATCH,2/2] spi: SPI fixes', - 'content': ''}, - ], - } - if series_id == 1234: - return { - 'patches': [ - {'id': 20, 'name': '[PATCH,v2,1/2] i2c: I2C things', - 'content': ''}, - {'id': 21, 'name': '[PATCH,v2,2/2] spi: SPI fixes', - 'content': ''}, - ], - } - raise ValueError(f'Fake Patchwork unknown series_id: {series_id}') - - # Read patch status - m_pat = re.search(r'patches/(\d*)/$', subpath) - patch_id = int(m_pat.group(1)) if m_pat else '' - if patch_id: - if patch_id in [10, 110]: - return {'state': 'accepted', - 'content': - 'Reviewed-by: Fred Bloggs <[email protected]>'} - if patch_id in [11, 111]: - return {'state': 'changes-requested', 'content': ''} - if patch_id in [12, 112]: - return {'state': 'rejected', - 'content': "I don't like this at all, sorry"} - if patch_id == 20: - return {'state': 'awaiting-upstream', 'content': ''} - if patch_id == 21: - return {'state': 'not-applicable', 'content': ''} - raise ValueError(f'Fake Patchwork unknown patch_id: {patch_id}') - - # Read comments a from patch - m_comm = re.search(r'patches/(\d*)/comments/', subpath) - patch_id = int(m_comm.group(1)) if m_comm else '' - if patch_id: - if patch_id in [10, 110]: - return [ - {'id': 1, 'content': ''}, - {'id': 2, - 'content': - '''On some date Mary Smith <[email protected]> wrote: -> This was my original patch -> which is being quoted - -I like the approach here and I would love to see more of it. - -Reviewed-by: Fred Bloggs <[email protected]> -''', - 'submitter': { - 'name': 'Fred Bloggs', - 'email': '[email protected]', - } - }, - ] - if patch_id in [11, 111]: - return [] - if patch_id in [12, 112]: - return [ - {'id': 4, 'content': ''}, - {'id': 5, 'content': ''}, - {'id': 6, 'content': ''}, - ] - if patch_id == 20: - return [ - {'id': 7, 'content': - '''On some date Alex Miller <[email protected]> wrote: - -> Sometimes we need to create a patch. -> This is one of those times - -Tested-by: Mary Smith <[email protected]> # yak -'''}, - {'id': 8, 'content': ''}, - ] - if patch_id == 21: - return [] - raise ValueError( - f'Fake Patchwork does not understand patch_id {patch_id}: ' - f'{subpath}') - - # Read comments from a cover letter - m_cover_id = re.search(r'covers/(\d*)/comments/', subpath) - cover_id = int(m_cover_id.group(1)) if m_cover_id else '' - if cover_id: - if cover_id in [39, 139]: - return [ - {'content': 'some comment', - 'submitter': { - 'name': 'A user', - 'email': '[email protected]', - }, - 'date': 'Sun 13 Apr 14:06:02 MDT 2025', - }, - {'content': 'another comment', - 'submitter': { - 'name': 'Ghenkis Khan', - 'email': '[email protected]', - }, - 'date': 'Sun 13 Apr 13:06:02 MDT 2025', - }, - ] - if cover_id == 29: - return [] - - raise ValueError(f'Fake Patchwork unknown cover_id: {cover_id}') - - raise ValueError(f'Fake Patchwork does not understand: {subpath}') - - def setup_second(self, do_sync=True): - """Set up the 'second' series synced with the fake patchwork - - Args: - do_sync (bool): True to sync the series - - Return: tuple: - Cseries: New Cseries object - pwork: Patchwork object - """ - with self.stage('setup second'): - cser = self.get_cser() - pwork = Patchwork.for_testing(self._fake_patchwork_cser) - pwork.project_set(self.PROJ_ID, self.PROJ_LINK_NAME) - - with terminal.capture() as (out, _): - cser.add('first', '', allow_unmarked=True) - cser.add('second', allow_unmarked=True) - - series = patchstream.get_metadata_for_list('second', self.gitdir, - 3) - self.assertEqual('456', series.links) - - with terminal.capture() as (out, _): - cser.increment('second') - - series = patchstream.get_metadata_for_list('second', self.gitdir, - 3) - self.assertEqual('456', series.links) - - series = patchstream.get_metadata_for_list('second2', self.gitdir, - 3) - self.assertEqual('1:456', series.links) - - if do_sync: - with terminal.capture() as (out, _): - cser.link_auto(pwork, 'second', 2, True) - with terminal.capture() as (out, _): - cser.gather(pwork, 'second', 2, False, True, False) - lines = out.getvalue().splitlines() - self.assertEqual( - "Updating series 'second' version 2 from link '457'", - lines[0]) - self.assertEqual( - '3 patches and cover letter updated (8 requests)', - lines[1]) - self.assertEqual(2, len(lines)) - - return cser, pwork - - def test_series_add_no_cover(self): - """Test patchwork when adding a series which has no cover letter""" - cser = self.get_cser() - pwork = Patchwork.for_testing(self._fake_patchwork_cser) - pwork.project_set(self.PROJ_ID, self.PROJ_LINK_NAME) - - with terminal.capture() as (out, _): - cser.add('first', 'my name for this', mark=False, - allow_unmarked=True) - self.assertIn("Added series 'first' v1 (2 commits)", out.getvalue()) - - with terminal.capture() as (out, _): - cser.link_auto(pwork, 'first', 1, True) - self.assertIn("Setting link for series 'first' v1 to 12345", - out.getvalue()) - - def test_series_list(self): - """Test listing cseries""" - self.setup_second() - - self.db_close() - args = Namespace(subcmd='ls') - with terminal.capture() as (out, _): - control.do_series(args, test_db=self.tmpdir, pwork=True) - lines = out.getvalue().splitlines() - self.assertEqual(5, len(lines)) - self.assertEqual( - 'Name Description ' - 'Accepted Versions', lines[0]) - self.assertTrue(lines[1].startswith('--')) - self.assertEqual( - 'first ' - ' -/2 1', lines[2]) - self.assertEqual( - 'second Series for my board ' - ' 1/3 1 2', lines[3]) - self.assertTrue(lines[4].startswith('--')) - - def test_do_series_add(self): - """Add a new cseries""" - self.make_git_tree() - args = Namespace(subcmd='add', desc='my-description', series='first', - mark=False, allow_unmarked=True, upstream=None, - dry_run=False) - with terminal.capture() as (out, _): - control.do_series(args, test_db=self.tmpdir, pwork=True) - - cser = self.get_database() - slist = cser.db.series_get_dict() - self.assertEqual(1, len(slist)) - ser = slist.get('first') - self.assertTrue(ser) - self.assertEqual('first', ser.name) - self.assertEqual('my-description', ser.desc) - - self.db_close() - args.subcmd = 'ls' - with terminal.capture() as (out, _): - control.do_series(args, test_db=self.tmpdir, pwork=True) - lines = out.getvalue().splitlines() - self.assertEqual(4, len(lines)) - self.assertTrue(lines[1].startswith('--')) - self.assertEqual( - 'first my-description ' - '-/2 1', lines[2]) - - def test_do_series_add_cmdline(self): - """Add a new cseries using the cmdline""" - self.make_git_tree() - with terminal.capture(): - self.run_args('series', '-s', 'first', 'add', '-M', - '-D', 'my-description', pwork=True) - - cser = self.get_database() - slist = cser.db.series_get_dict() - self.assertEqual(1, len(slist)) - ser = slist.get('first') - self.assertTrue(ser) - self.assertEqual('first', ser.name) - self.assertEqual('my-description', ser.desc) - - def test_do_series_add_auto(self): - """Add a new cseries without any arguments""" - self.make_git_tree() - - # Use the 'second' branch, which has a cover letter - gitutil.checkout('second', self.gitdir, work_tree=self.tmpdir, - force=True) - args = Namespace(subcmd='add', series=None, mark=False, - allow_unmarked=True, upstream=None, dry_run=False, - desc=None) - with terminal.capture(): - control.do_series(args, test_db=self.tmpdir, pwork=True) - - cser = self.get_database() - slist = cser.db.series_get_dict() - self.assertEqual(1, len(slist)) - ser = slist.get('second') - self.assertTrue(ser) - self.assertEqual('second', ser.name) - self.assertEqual('Series for my board', ser.desc) - cser.close_database() - - def _check_inc(self, out): - """Check output from an 'increment' operation - - Args: - out (StringIO): Text to check - """ - itr = iter(out.getvalue().splitlines()) - - self.assertEqual("Increment 'first' v1: 2 patches", next(itr)) - self.assertRegex(next(itr), 'Checking out upstream commit .*') - self.assertEqual("Processing 2 commits from branch 'first2'", - next(itr)) - self.assertRegex(next(itr), - f'- {HASH_RE} as {HASH_RE} i2c: I2C things') - self.assertRegex(next(itr), - f'- add v2: {HASH_RE} as {HASH_RE} spi: SPI fixes') - self.assertRegex( - next(itr), f'Updating branch first2 from {HASH_RE} to {HASH_RE}') - self.assertEqual('Added new branch first2', next(itr)) - return itr - - def test_series_link(self): - """Test adding a patchwork link to a cseries""" - cser = self.get_cser() - - repo = pygit2.init_repository(self.gitdir) - first = repo.lookup_branch('first').peel( - pygit2.enums.ObjectType.COMMIT).oid - base = repo.lookup_branch('base').peel( - pygit2.enums.ObjectType.COMMIT).oid - - gitutil.checkout('first', self.gitdir, work_tree=self.tmpdir, - force=True) - - with terminal.capture() as (out, _): - cser.add('first', '', allow_unmarked=True) - - with self.assertRaises(ValueError) as exc: - cser.link_set('first', 2, '1234', True) - self.assertEqual("Series 'first' does not have a version 2", - str(exc.exception)) - - self.assertEqual('first', gitutil.get_branch(self.gitdir)) - with terminal.capture() as (out, _): - cser.increment('first') - self.assertTrue(repo.lookup_branch('first2')) - - with terminal.capture() as (out, _): - cser.link_set('first', 2, '2345', True) - - lines = out.getvalue().splitlines() - self.assertEqual(6, len(lines)) - self.assertRegex( - lines[0], 'Checking out upstream commit refs/heads/base: .*') - self.assertEqual("Processing 2 commits from branch 'first2'", - lines[1]) - self.assertRegex( - lines[2], - f'- {HASH_RE} as {HASH_RE} i2c: I2C things') - self.assertRegex( - lines[3], - f"- add v2 links '2:2345': {HASH_RE} as {HASH_RE} spi: SPI fixes") - self.assertRegex( - lines[4], f'Updating branch first2 from {HASH_RE} to {HASH_RE}') - self.assertEqual("Setting link for series 'first' v2 to 2345", - lines[5]) - - self.assertEqual('2345', cser.link_get('first', 2)) - - series = patchstream.get_metadata_for_list('first2', self.gitdir, 2) - self.assertEqual('2:2345', series.links) - - self.assertEqual('first2', gitutil.get_branch(self.gitdir)) - - # Check the original series was left alone - self.assertEqual( - first, repo.lookup_branch('first').peel( - pygit2.enums.ObjectType.COMMIT).oid) - count = 2 - series1 = patchstream.get_metadata_for_list('first', self.gitdir, - count) - self.assertFalse('links' in series1) - self.assertFalse('version' in series1) - - # Check that base is left alone - self.assertEqual( - base, repo.lookup_branch('base').peel( - pygit2.enums.ObjectType.COMMIT).oid) - series1 = patchstream.get_metadata_for_list('base', self.gitdir, count) - self.assertFalse('links' in series1) - self.assertFalse('version' in series1) - - # Check out second and try to update first - gitutil.checkout('second', self.gitdir, work_tree=self.tmpdir, - force=True) - with terminal.capture(): - cser.link_set('first', 1, '16', True) - - # Overwrite the link - with terminal.capture(): - cser.link_set('first', 1, '17', True) - - series2 = patchstream.get_metadata_for_list('first', self.gitdir, - count) - self.assertEqual('1:17', series2.links) - - def test_series_link_cmdline(self): - """Test adding a patchwork link to a cseries using the cmdline""" - cser = self.get_cser() - - gitutil.checkout('first', self.gitdir, work_tree=self.tmpdir, - force=True) - - with terminal.capture() as (out, _): - cser.add('first', '', allow_unmarked=True) - - with terminal.capture() as (out, _): - self.run_args('series', '-s', 'first', '-V', '4', 'set-link', '-u', - '1234', expect_ret=1, pwork=True) - self.assertIn("Series 'first' does not have a version 4", - out.getvalue()) - - with self.assertRaises(ValueError) as exc: - cser.link_get('first', 4) - self.assertEqual("Series 'first' does not have a version 4", - str(exc.exception)) - - with terminal.capture() as (out, _): - cser.increment('first') - - with self.assertRaises(ValueError) as exc: - cser.link_get('first', 4) - self.assertEqual("Series 'first' does not have a version 4", - str(exc.exception)) - - with terminal.capture() as (out, _): - cser.increment('first') - cser.increment('first') - - with terminal.capture() as (out, _): - self.run_args('series', '-s', 'first', '-V', '4', 'set-link', '-u', - '1234', pwork=True) - lines = out.getvalue().splitlines() - self.assertRegex( - lines[-3], - f"- add v4 links '4:1234': {HASH_RE} as {HASH_RE} spi: SPI fixes") - self.assertEqual("Setting link for series 'first' v4 to 1234", - lines[-1]) - - with terminal.capture() as (out, _): - self.run_args('series', '-s', 'first', '-V', '4', 'get-link', - pwork=True) - self.assertIn('1234', out.getvalue()) - - series = patchstream.get_metadata_for_list('first4', self.gitdir, 1) - self.assertEqual('4:1234', series.links) - - with terminal.capture() as (out, _): - self.run_args('series', '-s', 'first', '-V', '5', 'get-link', - expect_ret=1, pwork=True) - - self.assertIn("Series 'first' does not have a version 5", - out.getvalue()) - - # Checkout 'first' and try to get the link from 'first4' - gitutil.checkout('first', self.gitdir, work_tree=self.tmpdir, - force=True) - - with terminal.capture() as (out, _): - self.run_args('series', '-s', 'first4', 'get-link', pwork=True) - self.assertIn('1234', out.getvalue()) - - # This should get the link for 'first' - with terminal.capture() as (out, _): - self.run_args('series', 'get-link', pwork=True) - self.assertIn('None', out.getvalue()) - - # Checkout 'first4' again; this should get the link for 'first4' - gitutil.checkout('first4', self.gitdir, work_tree=self.tmpdir, - force=True) - - with terminal.capture() as (out, _): - self.run_args('series', 'get-link', pwork=True) - self.assertIn('1234', out.getvalue()) - - def test_series_link_auto_version(self): - """Test finding the patchwork link for a cseries automatically""" - cser = self.get_cser() - - with terminal.capture() as (out, _): - cser.add('second', allow_unmarked=True) - - # Make sure that the link is there - count = 3 - series = patchstream.get_metadata('second', 0, count, - git_dir=self.gitdir) - self.assertEqual(f'{self.SERIES_ID_SECOND_V1}', series.links) - - # Set link with detected version - with terminal.capture() as (out, _): - cser.link_set('second', None, f'{self.SERIES_ID_SECOND_V1}', True) - self.assertEqual( - "Setting link for series 'second' v1 to 456", - out.getvalue().splitlines()[-1]) - - # Make sure that the link was set - series = patchstream.get_metadata('second', 0, count, - git_dir=self.gitdir) - self.assertEqual(f'1:{self.SERIES_ID_SECOND_V1}', series.links) - - with terminal.capture(): - cser.increment('second') - - # Make sure that the new series gets the same link - series = patchstream.get_metadata('second2', 0, 3, - git_dir=self.gitdir) - - pwork = Patchwork.for_testing(self._fake_patchwork_cser) - pwork.project_set(self.PROJ_ID, self.PROJ_LINK_NAME) - self.assertFalse(cser.project_get()) - cser.project_set(pwork, 'U-Boot', quiet=True) - - self.assertEqual( - (self.SERIES_ID_SECOND_V1, None, 'second', 1, - 'Series for my board'), - cser.link_search(pwork, 'second', 1)) - - with terminal.capture(): - cser.increment('second') - - self.assertEqual((457, None, 'second', 2, 'Series for my board'), - cser.link_search(pwork, 'second', 2)) - - def test_series_link_auto_name(self): - """Test finding the patchwork link for a cseries with auto name""" - cser = self.get_cser() - - with terminal.capture() as (out, _): - cser.add('first', '', allow_unmarked=True) - - # Set link with detected name - with self.assertRaises(ValueError) as exc: - cser.link_set(None, 2, '2345', True) - self.assertEqual( - "Series 'first' does not have a version 2", str(exc.exception)) - - with terminal.capture(): - cser.increment('first') - - with terminal.capture() as (out, _): - cser.link_set(None, 2, '2345', True) - self.assertEqual( - "Setting link for series 'first' v2 to 2345", - out.getvalue().splitlines()[-1]) - - svlist = cser.get_ser_ver_list() - self.assertEqual(2, len(svlist)) - self.assertEqual(1, svlist[0].idnum) - self.assertEqual(1, svlist[0].series_id) - self.assertEqual(1, svlist[0].version) - self.assertIsNone(svlist[0].link) - - self.assertEqual(2, svlist[1].idnum) - self.assertEqual(1, svlist[1].series_id) - self.assertEqual(2, svlist[1].version) - self.assertEqual('2345', svlist[1].link) - - def test_series_link_auto_name_version(self): - """Find patchwork link for a cseries with auto name + version""" - cser = self.get_cser() - - with terminal.capture() as (out, _): - cser.add('first', '', allow_unmarked=True) - - # Set link with detected name and version - with terminal.capture() as (out, _): - cser.link_set(None, None, '1234', True) - self.assertEqual( - "Setting link for series 'first' v1 to 1234", - out.getvalue().splitlines()[-1]) - - with terminal.capture(): - cser.increment('first') - - with terminal.capture() as (out, _): - cser.link_set(None, None, '2345', True) - self.assertEqual( - "Setting link for series 'first' v2 to 2345", - out.getvalue().splitlines()[-1]) - - svlist = cser.get_ser_ver_list() - self.assertEqual(2, len(svlist)) - self.assertEqual(1, svlist[0].idnum) - self.assertEqual(1, svlist[0].series_id) - self.assertEqual(1, svlist[0].version) - self.assertEqual('1234', svlist[0].link) - - self.assertEqual(2, svlist[1].idnum) - self.assertEqual(1, svlist[1].series_id) - self.assertEqual(2, svlist[1].version) - self.assertEqual('2345', svlist[1].link) - - def test_series_link_missing(self): - """Test finding patchwork link for a cseries but it is missing""" - cser = self.get_cser() - - with terminal.capture(): - cser.add('second', allow_unmarked=True) - - with terminal.capture(): - cser.increment('second') - cser.increment('second') - - pwork = Patchwork.for_testing(self._fake_patchwork_cser) - pwork.project_set(self.PROJ_ID, self.PROJ_LINK_NAME) - self.assertFalse(cser.project_get()) - cser.project_set(pwork, 'U-Boot', quiet=True) - - self.assertEqual( - (self.SERIES_ID_SECOND_V1, None, 'second', 1, - 'Series for my board'), - cser.link_search(pwork, 'second', 1)) - self.assertEqual((457, None, 'second', 2, 'Series for my board'), - cser.link_search(pwork, 'second', 2)) - res = cser.link_search(pwork, 'second', 3) - self.assertEqual( - (None, - [{'id': self.SERIES_ID_SECOND_V1, 'name': 'Series for my board', - 'version': 1}, - {'id': 457, 'name': 'Series for my board', 'version': 2}], - 'second', 3, 'Series for my board'), - res) - - def check_series_autolink(self): - """Common code for autolink tests""" - cser = self.get_cser() - - with self.stage('setup'): - pwork = Patchwork.for_testing(self._fake_patchwork_cser) - pwork.project_set(self.PROJ_ID, self.PROJ_LINK_NAME) - self.assertFalse(cser.project_get()) - cser.project_set(pwork, 'U-Boot', quiet=True) - - with terminal.capture(): - cser.add('first', '', allow_unmarked=True) - cser.add('second', allow_unmarked=True) - - with self.stage('autolink unset'): - with terminal.capture() as (out, _): - yield cser, pwork - self.assertEqual( - "Setting link for series 'second' v1 to " - f'{self.SERIES_ID_SECOND_V1}', - out.getvalue().splitlines()[-1]) - - svlist = cser.get_ser_ver_list() - self.assertEqual(2, len(svlist)) - self.assertEqual(1, svlist[0].idnum) - self.assertEqual(1, svlist[0].series_id) - self.assertEqual(1, svlist[0].version) - self.assertEqual(2, svlist[1].idnum) - self.assertEqual(2, svlist[1].series_id) - self.assertEqual(1, svlist[1].version) - self.assertEqual(str(self.SERIES_ID_SECOND_V1), svlist[1].link) - yield None - - def test_series_autolink(self): - """Test linking a cseries to its patchwork series by description""" - cor = self.check_series_autolink() - cser, pwork = next(cor) - - with self.assertRaises(ValueError) as exc: - cser.link_auto(pwork, 'first', None, True) - self.assertIn("Series 'first' has an empty description", - str(exc.exception)) - - # autolink unset - cser.link_auto(pwork, 'second', None, True) - - self.assertFalse(next(cor)) - cor.close() - - def test_series_autolink_cmdline(self): - """Test linking to patchwork series by description on cmdline""" - cor = self.check_series_autolink() - _, pwork = next(cor) - - with terminal.capture() as (out, _): - self.run_args('series', '-s', 'first', 'autolink', expect_ret=1, - pwork=pwork) - self.assertEqual( - "patman: ValueError: Series 'first' has an empty description", - out.getvalue().strip()) - - # autolink unset - self.run_args('series', '-s', 'second', 'autolink', '-u', pwork=pwork) - - self.assertFalse(next(cor)) - cor.close() - - def _autolink_setup(self): - """Set things up for autolink tests - - Return: tuple: - Cseries object - Patchwork object - """ - cser = self.get_cser() - - pwork = Patchwork.for_testing(self._fake_patchwork_cser) - pwork.project_set(self.PROJ_ID, self.PROJ_LINK_NAME) - self.assertFalse(cser.project_get()) - cser.project_set(pwork, 'U-Boot', quiet=True) - - with terminal.capture(): - cser.add('first', 'first series', allow_unmarked=True) - cser.add('second', allow_unmarked=True) - cser.increment('first') - return cser, pwork - - def test_series_link_auto_all(self): - """Test linking all cseries to their patchwork series by description""" - cser, pwork = self._autolink_setup() - with terminal.capture() as (out, _): - summary = cser.link_auto_all(pwork, update_commit=True, - link_all_versions=True, - replace_existing=False, dry_run=True, - show_summary=False) - self.assertEqual(3, len(summary)) - items = iter(summary.values()) - linked = next(items) - self.assertEqual( - ('first', 1, None, 'first series', 'linked:1234'), linked) - self.assertEqual( - ('first', 2, None, 'first series', 'not found'), next(items)) - self.assertEqual( - ('second', 1, f'{self.SERIES_ID_SECOND_V1}', 'Series for my board', - f'already:{self.SERIES_ID_SECOND_V1}'), - next(items)) - self.assertEqual('Dry run completed', out.getvalue().splitlines()[-1]) - - # A second dry run should do exactly the same thing - with terminal.capture() as (out2, _): - summary2 = cser.link_auto_all(pwork, update_commit=True, - link_all_versions=True, - replace_existing=False, dry_run=True, - show_summary=False) - self.assertEqual(out.getvalue(), out2.getvalue()) - self.assertEqual(summary, summary2) - - # Now do it for real - with terminal.capture(): - summary = cser.link_auto_all(pwork, update_commit=True, - link_all_versions=True, - replace_existing=False, dry_run=False, - show_summary=False) - - # Check the link was updated - pdict = cser.get_ser_ver_dict() - svid = list(summary)[0] - self.assertEqual('1234', pdict[svid].link) - - series = patchstream.get_metadata_for_list('first', self.gitdir, 2) - self.assertEqual('1:1234', series.links) - - def test_series_autolink_latest(self): - """Test linking the lastest versions""" - cser, pwork = self._autolink_setup() - with terminal.capture(): - summary = cser.link_auto_all(pwork, update_commit=True, - link_all_versions=False, - replace_existing=False, dry_run=False, - show_summary=False) - self.assertEqual(2, len(summary)) - items = iter(summary.values()) - self.assertEqual( - ('first', 2, None, 'first series', 'not found'), next(items)) - self.assertEqual( - ('second', 1, f'{self.SERIES_ID_SECOND_V1}', 'Series for my board', - f'already:{self.SERIES_ID_SECOND_V1}'), - next(items)) - - def test_series_autolink_no_update(self): - """Test linking the lastest versions without updating commits""" - cser, pwork = self._autolink_setup() - with terminal.capture(): - cser.link_auto_all(pwork, update_commit=False, - link_all_versions=True, replace_existing=False, - dry_run=False, - show_summary=False) - - series = patchstream.get_metadata_for_list('first', self.gitdir, 2) - self.assertNotIn('links', series) - - def test_series_autolink_replace(self): - """Test linking the lastest versions without updating commits""" - cser, pwork = self._autolink_setup() - with terminal.capture(): - summary = cser.link_auto_all(pwork, update_commit=True, - link_all_versions=True, - replace_existing=True, dry_run=False, - show_summary=False) - self.assertEqual(3, len(summary)) - items = iter(summary.values()) - linked = next(items) - self.assertEqual( - ('first', 1, None, 'first series', 'linked:1234'), linked) - self.assertEqual( - ('first', 2, None, 'first series', 'not found'), next(items)) - self.assertEqual( - ('second', 1, f'{self.SERIES_ID_SECOND_V1}', 'Series for my board', - f'linked:{self.SERIES_ID_SECOND_V1}'), - next(items)) - - def test_series_autolink_extra(self): - """Test command-line operation - - This just uses mocks for now since we can rely on the direct tests for - the actual operation. - """ - _, pwork = self._autolink_setup() - with (mock.patch.object(cseries.Cseries, 'link_auto_all', - return_value=None) as method): - self.run_args('series', 'autolink-all', pwork=True) - method.assert_called_once_with(True, update_commit=False, - link_all_versions=False, - replace_existing=False, dry_run=False, - show_summary=True) - - with (mock.patch.object(cseries.Cseries, 'link_auto_all', - return_value=None) as method): - self.run_args('series', 'autolink-all', '-a', pwork=True) - method.assert_called_once_with(True, update_commit=False, - link_all_versions=True, - replace_existing=False, dry_run=False, - show_summary=True) - - with (mock.patch.object(cseries.Cseries, 'link_auto_all', - return_value=None) as method): - self.run_args('series', 'autolink-all', '-a', '-r', pwork=True) - method.assert_called_once_with(True, update_commit=False, - link_all_versions=True, - replace_existing=True, dry_run=False, - show_summary=True) - - with (mock.patch.object(cseries.Cseries, 'link_auto_all', - return_value=None) as method): - self.run_args('series', '-n', 'autolink-all', '-r', pwork=True) - method.assert_called_once_with(True, update_commit=False, - link_all_versions=False, - replace_existing=True, dry_run=True, - show_summary=True) - - with (mock.patch.object(cseries.Cseries, 'link_auto_all', - return_value=None) as method): - self.run_args('series', 'autolink-all', '-u', pwork=True) - method.assert_called_once_with(True, update_commit=True, - link_all_versions=False, - replace_existing=False, dry_run=False, - show_summary=True) - - # Now do a real one to check the patchwork handling and output - with terminal.capture() as (out, _): - self.run_args('series', 'autolink-all', '-a', pwork=pwork) - itr = iter(out.getvalue().splitlines()) - self.assertEqual( - '1 series linked, 1 already linked, 1 not found (3 requests)', - next(itr)) - self.assertEqual('', next(itr)) - self.assertEqual( - 'Name Version Description ' - ' Result', next(itr)) - self.assertTrue(next(itr).startswith('--')) - self.assertEqual( - 'first 1 first series ' - ' linked:1234', next(itr)) - self.assertEqual( - 'first 2 first series ' - ' not found', next(itr)) - self.assertEqual( - 'second 1 Series for my board ' - f' already:{self.SERIES_ID_SECOND_V1}', - next(itr)) - self.assertTrue(next(itr).startswith('--')) - self.assert_finished(itr) - - def check_series_archive(self): - """Coroutine to run the archive test""" - cser = self.get_cser() - with self.stage('setup'): - with terminal.capture(): - cser.add('first', '', allow_unmarked=True) - - # Check the series is visible in the list - slist = cser.db.series_get_dict() - self.assertEqual(1, len(slist)) - self.assertEqual('first', slist['first'].name) - - # Add a second branch - with terminal.capture(): - cser.increment('first') - - cser.fake_now = datetime(24, 9, 14) - repo = pygit2.init_repository(self.gitdir) - with self.stage('archive'): - expected_commit1 = repo.revparse_single('first') - expected_commit2 = repo.revparse_single('first2') - expected_tag1 = 'first-14sep24' - expected_tag2 = 'first2-14sep24' - - # Archive it and make sure it is invisible - yield cser - slist = cser.db.series_get_dict() - self.assertFalse(slist) - - # ...unless we include archived items - slist = cser.db.series_get_dict(include_archived=True) - self.assertEqual(1, len(slist)) - first = slist['first'] - self.assertEqual('first', first.name) - - # Make sure the branches have been tagged - svlist = cser.db.ser_ver_get_for_series(first.idnum) - self.assertEqual(expected_tag1, svlist[0].archive_tag) - self.assertEqual(expected_tag2, svlist[1].archive_tag) - - # Check that the tags were created and point to old branch commits - target1 = repo.revparse_single(expected_tag1) - self.assertEqual(expected_commit1, target1.get_object()) - target2 = repo.revparse_single(expected_tag2) - self.assertEqual(expected_commit2, target2.get_object()) - - # The branches should be deleted - self.assertFalse('first' in repo.branches) - self.assertFalse('first2' in repo.branches) - - with self.stage('unarchive'): - # or we unarchive it - yield cser - slist = cser.db.series_get_dict() - self.assertEqual(1, len(slist)) - - # Make sure the branches have been restored - branch1 = repo.branches['first'] - branch2 = repo.branches['first2'] - self.assertEqual(expected_commit1.oid, branch1.target) - self.assertEqual(expected_commit2.oid, branch2.target) - - # Make sure the tags were deleted - try: - target1 = repo.revparse_single(expected_tag1) - self.fail('target1 is still present') - except KeyError: - pass - try: - target1 = repo.revparse_single(expected_tag2) - self.fail('target2 is still present') - except KeyError: - pass - - # Make sure the tag information has been removed - svlist = cser.db.ser_ver_get_for_series(first.idnum) - self.assertFalse(svlist[0].archive_tag) - self.assertFalse(svlist[1].archive_tag) - - yield False - - def test_series_archive(self): - """Test marking a series as archived""" - cor = self.check_series_archive() - cser = next(cor) - - # Archive it and make sure it is invisible - cser.archive('first') - cser = next(cor) - cser.unarchive('first') - self.assertFalse(next(cor)) - cor.close() - - def test_series_archive_cmdline(self): - """Test marking a series as archived with cmdline""" - cor = self.check_series_archive() - cser = next(cor) - - # Archive it and make sure it is invisible - self.run_args('series', '-s', 'first', 'archive', pwork=True, - cser=cser) - next(cor) - self.run_args('series', '-s', 'first', 'unarchive', pwork=True, - cser=cser) - self.assertFalse(next(cor)) - cor.close() - - def check_series_inc(self): - """Coroutine to run the increment test""" - cser = self.get_cser() - - with self.stage('setup'): - gitutil.checkout('first', self.gitdir, work_tree=self.tmpdir, - force=True) - with terminal.capture() as (out, _): - cser.add('first', '', allow_unmarked=True) - - with self.stage('increment'): - with terminal.capture() as (out, _): - yield cser - self._check_inc(out) - - slist = cser.db.series_get_dict() - self.assertEqual(1, len(slist)) - - svlist = cser.get_ser_ver_list() - self.assertEqual(2, len(svlist)) - self.assertEqual(1, svlist[0].idnum) - self.assertEqual(1, svlist[0].series_id) - self.assertEqual(1, svlist[0].version) - - self.assertEqual(2, svlist[1].idnum) - self.assertEqual(1, svlist[1].series_id) - self.assertEqual(2, svlist[1].version) - - series = patchstream.get_metadata_for_list('first2', self.gitdir, - 1) - self.assertEqual('2', series.version) - - series = patchstream.get_metadata_for_list('first', self.gitdir, 1) - self.assertNotIn('version', series) - - self.assertEqual('first2', gitutil.get_branch(self.gitdir)) - yield None - - def test_series_inc(self): - """Test incrementing the version""" - cor = self.check_series_inc() - cser = next(cor) - - cser.increment('first') - self.assertFalse(next(cor)) - - cor.close() - - def test_series_inc_cmdline(self): - """Test incrementing the version with cmdline""" - cor = self.check_series_inc() - next(cor) - - self.run_args('series', '-s', 'first', 'inc', pwork=True) - self.assertFalse(next(cor)) - cor.close() - - def test_series_inc_no_upstream(self): - """Increment a series which has no upstream branch""" - cser = self.get_cser() - - gitutil.checkout('first', self.gitdir, work_tree=self.tmpdir, - force=True) - with terminal.capture(): - cser.add('first', '', allow_unmarked=True) - - repo = pygit2.init_repository(self.gitdir) - upstream = repo.lookup_branch('base') - upstream.delete() - with terminal.capture(): - cser.increment('first') - - slist = cser.db.series_get_dict() - self.assertEqual(1, len(slist)) - - def test_series_inc_dryrun(self): - """Test incrementing the version with cmdline""" - cser = self.get_cser() - - gitutil.checkout('first', self.gitdir, work_tree=self.tmpdir, - force=True) - with terminal.capture() as (out, _): - cser.add('first', '', allow_unmarked=True) - - with terminal.capture() as (out, _): - cser.increment('first', dry_run=True) - itr = self._check_inc(out) - self.assertEqual('Dry run completed', next(itr)) - - # Make sure that nothing was added - svlist = cser.get_ser_ver_list() - self.assertEqual(1, len(svlist)) - self.assertEqual(1, svlist[0].idnum) - self.assertEqual(1, svlist[0].series_id) - self.assertEqual(1, svlist[0].version) - - # We should still be on the same branch - self.assertEqual('first', gitutil.get_branch(self.gitdir)) - - def test_series_dec(self): - """Test decrementing the version""" - cser = self.get_cser() - - gitutil.checkout('first', self.gitdir, work_tree=self.tmpdir, - force=True) - with terminal.capture() as (out, _): - cser.add('first', '', allow_unmarked=True) - - pclist = cser.get_pcommit_dict() - self.assertEqual(2, len(pclist)) - - # Try decrementing when there is only one version - with self.assertRaises(ValueError) as exc: - cser.decrement('first') - self.assertEqual("Series 'first' only has one version", - str(exc.exception)) - - # Add a version; now there should be two - with terminal.capture() as (out, _): - cser.increment('first') - svdict = cser.get_ser_ver_dict() - self.assertEqual(2, len(svdict)) - - pclist = cser.get_pcommit_dict() - self.assertEqual(4, len(pclist)) - - # Remove version two, using dry run (i.e. no effect) - with terminal.capture() as (out, _): - cser.decrement('first', dry_run=True) - svdict = cser.get_ser_ver_dict() - self.assertEqual(2, len(svdict)) - - repo = pygit2.init_repository(self.gitdir) - branch = repo.lookup_branch('first2') - self.assertTrue(branch) - branch_oid = branch.peel(pygit2.enums.ObjectType.COMMIT).oid - - pclist = cser.get_pcommit_dict() - self.assertEqual(4, len(pclist)) - - # Now remove version two for real - with terminal.capture() as (out, _): - cser.decrement('first') - lines = out.getvalue().splitlines() - self.assertEqual(2, len(lines)) - self.assertEqual("Removing series 'first' v2", lines[0]) - self.assertEqual( - f"Deleted branch 'first2' {str(branch_oid)[:10]}", lines[1]) - - svdict = cser.get_ser_ver_dict() - self.assertEqual(1, len(svdict)) - - pclist = cser.get_pcommit_dict() - self.assertEqual(2, len(pclist)) - - branch = repo.lookup_branch('first2') - self.assertFalse(branch) - - # Removing the only version should not be allowed - with self.assertRaises(ValueError) as exc: - cser.decrement('first', dry_run=True) - self.assertEqual("Series 'first' only has one version", - str(exc.exception)) - - def test_upstream_add(self): - """Test adding an upsream""" - cser = self.get_cser() - - cser.upstream_add('us', 'https://one') - ulist = cser.get_upstream_dict() - self.assertEqual(1, len(ulist)) - self.assertEqual(('https://one', None), ulist['us']) - - cser.upstream_add('ci', 'git@two') - ulist = cser.get_upstream_dict() - self.assertEqual(2, len(ulist)) - self.assertEqual(('https://one', None), ulist['us']) - self.assertEqual(('git@two', None), ulist['ci']) - - # Try to add a duplicate - with self.assertRaises(ValueError) as exc: - cser.upstream_add('ci', 'git@three') - self.assertEqual("Upstream 'ci' already exists", str(exc.exception)) - - with terminal.capture() as (out, _): - cser.upstream_list() - lines = out.getvalue().splitlines() - self.assertEqual(2, len(lines)) - self.assertEqual('us https://one', lines[0]) - self.assertEqual('ci git@two', lines[1]) - - def test_upstream_add_cmdline(self): - """Test adding an upsream with cmdline""" - with terminal.capture(): - self.run_args('upstream', 'add', 'us', 'https://one') - - with terminal.capture() as (out, _): - self.run_args('upstream', 'list') - lines = out.getvalue().splitlines() - self.assertEqual(1, len(lines)) - self.assertEqual('us https://one', lines[0]) - - def test_upstream_default(self): - """Operation of the default upstream""" - cser = self.get_cser() - - with self.assertRaises(ValueError) as exc: - cser.upstream_set_default('us') - self.assertEqual("No such upstream 'us'", str(exc.exception)) - - cser.upstream_add('us', 'https://one') - cser.upstream_add('ci', 'git@two') - - self.assertIsNone(cser.upstream_get_default()) - - cser.upstream_set_default('us') - self.assertEqual('us', cser.upstream_get_default()) - - cser.upstream_set_default('us') - - cser.upstream_set_default('ci') - self.assertEqual('ci', cser.upstream_get_default()) - - with terminal.capture() as (out, _): - cser.upstream_list() - lines = out.getvalue().splitlines() - self.assertEqual(2, len(lines)) - self.assertEqual('us https://one', lines[0]) - self.assertEqual('ci default git@two', lines[1]) - - cser.upstream_set_default(None) - self.assertIsNone(cser.upstream_get_default()) - - def test_upstream_default_cmdline(self): - """Operation of the default upstream on cmdline""" - with terminal.capture() as (out, _): - self.run_args('upstream', 'default', 'us', expect_ret=1) - self.assertEqual("patman: ValueError: No such upstream 'us'", - out.getvalue().strip().splitlines()[-1]) - - self.run_args('upstream', 'add', 'us', 'https://one') - self.run_args('upstream', 'add', 'ci', 'git@two') - - with terminal.capture() as (out, _): - self.run_args('upstream', 'default') - self.assertEqual('unset', out.getvalue().strip()) - - self.run_args('upstream', 'default', 'us') - with terminal.capture() as (out, _): - self.run_args('upstream', 'default') - self.assertEqual('us', out.getvalue().strip()) - - self.run_args('upstream', 'default', 'ci') - with terminal.capture() as (out, _): - self.run_args('upstream', 'default') - self.assertEqual('ci', out.getvalue().strip()) - - with terminal.capture() as (out, _): - self.run_args('upstream', 'default', '--unset') - self.assertFalse(out.getvalue().strip()) - - with terminal.capture() as (out, _): - self.run_args('upstream', 'default') - self.assertEqual('unset', out.getvalue().strip()) - - def test_upstream_delete(self): - """Test operation of the default upstream""" - cser = self.get_cser() - - with self.assertRaises(ValueError) as exc: - cser.upstream_delete('us') - self.assertEqual("No such upstream 'us'", str(exc.exception)) - - cser.upstream_add('us', 'https://one') - cser.upstream_add('ci', 'git@two') - - cser.upstream_set_default('us') - cser.upstream_delete('us') - self.assertIsNone(cser.upstream_get_default()) - - cser.upstream_delete('ci') - ulist = cser.get_upstream_dict() - self.assertFalse(ulist) - - def test_upstream_delete_cmdline(self): - """Test deleting an upstream""" - with terminal.capture() as (out, _): - self.run_args('upstream', 'delete', 'us', expect_ret=1) - self.assertEqual("patman: ValueError: No such upstream 'us'", - out.getvalue().strip().splitlines()[-1]) - - self.run_args('us', 'add', 'us', 'https://one') - self.run_args('us', 'add', 'ci', 'git@two') - - self.run_args('upstream', 'default', 'us') - self.run_args('upstream', 'delete', 'us') - with terminal.capture() as (out, _): - self.run_args('upstream', 'default', 'us', expect_ret=1) - self.assertEqual("patman: ValueError: No such upstream 'us'", - out.getvalue().strip()) - - self.run_args('upstream', 'delete', 'ci') - with terminal.capture() as (out, _): - self.run_args('upstream', 'list') - self.assertFalse(out.getvalue().strip()) - - def test_series_add_mark(self): - """Test marking a cseries with Change-Id fields""" - cser = self.get_cser() - - with terminal.capture(): - cser.add('first', '', mark=True) - - pcdict = cser.get_pcommit_dict() - - series = patchstream.get_metadata('first', 0, 2, git_dir=self.gitdir) - self.assertEqual(2, len(series.commits)) - self.assertIn(1, pcdict) - self.assertEqual(1, pcdict[1].idnum) - self.assertEqual('i2c: I2C things', pcdict[1].subject) - self.assertEqual(1, pcdict[1].svid) - self.assertEqual(series.commits[0].change_id, pcdict[1].change_id) - - self.assertIn(2, pcdict) - self.assertEqual(2, pcdict[2].idnum) - self.assertEqual('spi: SPI fixes', pcdict[2].subject) - self.assertEqual(1, pcdict[2].svid) - self.assertEqual(series.commits[1].change_id, pcdict[2].change_id) - - def test_series_add_mark_fail(self): - """Test marking a cseries when the tree is dirty""" - cser = self.get_cser() - - tools.write_file(os.path.join(self.tmpdir, 'fname'), b'123') - with terminal.capture(): - cser.add('first', '', mark=True) - - tools.write_file(os.path.join(self.tmpdir, 'i2c.c'), b'123') - with self.assertRaises(ValueError) as exc: - with terminal.capture(): - cser.add('first', '', mark=True) - self.assertEqual( - "Modified files exist: use 'git status' to check: [' M i2c.c']", - str(exc.exception)) - - def test_series_add_mark_dry_run(self): - """Test marking a cseries with Change-Id fields""" - cser = self.get_cser() - - with terminal.capture() as (out, _): - cser.add('first', '', mark=True, dry_run=True) - itr = iter(out.getvalue().splitlines()) - self.assertEqual( - "Adding series 'first' v1: mark True allow_unmarked False", - next(itr)) - self.assertRegex( - next(itr), 'Checking out upstream commit refs/heads/base: .*') - self.assertEqual("Processing 2 commits from branch 'first'", - next(itr)) - self.assertRegex( - next(itr), f'- marked: {HASH_RE} as {HASH_RE} i2c: I2C things') - self.assertRegex( - next(itr), f'- marked: {HASH_RE} as {HASH_RE} spi: SPI fixes') - self.assertRegex( - next(itr), f'Updating branch first from {HASH_RE} to {HASH_RE}') - self.assertEqual("Added series 'first' v1 (2 commits)", - next(itr)) - self.assertEqual('Dry run completed', next(itr)) - - # Doing another dry run should produce the same result - with terminal.capture() as (out2, _): - cser.add('first', '', mark=True, dry_run=True) - self.assertEqual(out.getvalue(), out2.getvalue()) - - tools.write_file(os.path.join(self.tmpdir, 'i2c.c'), b'123') - with terminal.capture() as (out, _): - with self.assertRaises(ValueError) as exc: - cser.add('first', '', mark=True, dry_run=True) - self.assertEqual( - "Modified files exist: use 'git status' to check: [' M i2c.c']", - str(exc.exception)) - - pcdict = cser.get_pcommit_dict() - self.assertFalse(pcdict) - - def test_series_add_mark_cmdline(self): - """Test marking a cseries with Change-Id fields using the cmdline""" - cser = self.get_cser() - - with terminal.capture(): - self.run_args('series', '-s', 'first', 'add', '-m', - '-D', 'my-description', pwork=True) - - pcdict = cser.get_pcommit_dict() - self.assertTrue(pcdict[1].change_id) - self.assertTrue(pcdict[2].change_id) - - def test_series_add_unmarked_cmdline(self): - """Test adding an unmarked cseries using the command line""" - cser = self.get_cser() - - with terminal.capture(): - self.run_args('series', '-s', 'first', 'add', '-M', - '-D', 'my-description', pwork=True) - - pcdict = cser.get_pcommit_dict() - self.assertFalse(pcdict[1].change_id) - self.assertFalse(pcdict[2].change_id) - - def test_series_add_unmarked_bad_cmdline(self): - """Test failure to add an unmarked cseries using a bad command line""" - self.get_cser() - - with terminal.capture() as (out, _): - self.run_args('series', '-s', 'first', 'add', - '-D', 'my-description', expect_ret=1, pwork=True) - last_line = out.getvalue().splitlines()[-2] - self.assertEqual( - 'patman: ValueError: 2 commit(s) are unmarked; ' - 'please use -m or -M', last_line) - - def check_series_unmark(self): - """Checker for unmarking tests""" - cser = self.get_cser() - with self.stage('unmarked commits'): - yield cser - - with self.stage('mark commits'): - with terminal.capture() as (out, _): - yield cser - - with self.stage('unmark: dry run'): - with terminal.capture() as (out, _): - yield cser - - itr = iter(out.getvalue().splitlines()) - self.assertEqual( - "Unmarking series 'first': allow_unmarked False", - next(itr)) - self.assertRegex( - next(itr), 'Checking out upstream commit refs/heads/base: .*') - self.assertEqual("Processing 2 commits from branch 'first'", - next(itr)) - self.assertRegex( - next(itr), - f'- unmarked: {HASH_RE} as {HASH_RE} i2c: I2C things') - self.assertRegex( - next(itr), - f'- unmarked: {HASH_RE} as {HASH_RE} spi: SPI fixes') - self.assertRegex( - next(itr), f'Updating branch first from {HASH_RE} to {HASH_RE}') - self.assertEqual('Dry run completed', next(itr)) - - with self.stage('unmark'): - with terminal.capture() as (out, _): - yield cser - self.assertIn('- unmarked', out.getvalue()) - - with self.stage('unmark: allow unmarked'): - with terminal.capture() as (out, _): - yield cser - self.assertIn('- no mark', out.getvalue()) - - yield None - - def test_series_unmark(self): - """Test unmarking a cseries, i.e. removing Change-Id fields""" - cor = self.check_series_unmark() - cser = next(cor) - - # check the allow_unmarked flag - with terminal.capture(): - with self.assertRaises(ValueError) as exc: - cser.unmark('first', dry_run=True) - self.assertEqual('Unmarked commits 2/2', str(exc.exception)) - - # mark commits - cser = next(cor) - cser.add('first', '', mark=True) - - # unmark: dry run - cser = next(cor) - cser.unmark('first', dry_run=True) - - # unmark - cser = next(cor) - cser.unmark('first') - - # unmark: allow unmarked - cser = next(cor) - cser.unmark('first', allow_unmarked=True) - - self.assertFalse(next(cor)) - - def test_series_unmark_cmdline(self): - """Test the unmark command""" - cor = self.check_series_unmark() - next(cor) - - # check the allow_unmarked flag - with terminal.capture() as (out, _): - self.run_args('series', 'unmark', expect_ret=1, pwork=True) - self.assertIn('Unmarked commits 2/2', out.getvalue()) - - # mark commits - next(cor) - self.run_args('series', '-s', 'first', 'add', '-D', '', '--mark', - pwork=True) - - # unmark: dry run - next(cor) - self.run_args('series', '-s', 'first', '-n', 'unmark', pwork=True) - - # unmark - next(cor) - self.run_args('series', '-s', 'first', 'unmark', pwork=True) - - # unmark: allow unmarked - next(cor) - self.run_args('series', '-s', 'first', 'unmark', '--allow-unmarked', - pwork=True) - - self.assertFalse(next(cor)) - - def test_series_unmark_middle(self): - """Test unmarking with Change-Id fields not last in the commit""" - cser = self.get_cser() - with terminal.capture(): - cser.add('first', '', allow_unmarked=True) - - # Add some change IDs in the middle of the commit message - with terminal.capture(): - name, ser, _, _ = cser.prep_series('first') - old_msgs = [] - for vals in cser.process_series(name, ser): - old_msgs.append(vals.msg) - lines = vals.msg.splitlines() - change_id = cser.make_change_id(vals.commit) - extra = [f'{cser_helper.CHANGE_ID_TAG}: {change_id}'] - vals.msg = '\n'.join(lines[:2] + extra + lines[2:]) + '\n' - - with terminal.capture(): - cser.unmark('first') - - # We should get back the original commit message - series = patchstream.get_metadata('first', 0, 2, git_dir=self.gitdir) - self.assertEqual(old_msgs[0], series.commits[0].msg) - self.assertEqual(old_msgs[1], series.commits[1].msg) - - def check_series_mark(self): - """Checker for marking tests""" - cser = self.get_cser() - yield cser - - # Start with a dry run, which should do nothing - with self.stage('dry run'): - with terminal.capture(): - yield cser - - series = patchstream.get_metadata_for_list('first', self.gitdir, 2) - self.assertEqual(2, len(series.commits)) - self.assertFalse(series.commits[0].change_id) - self.assertFalse(series.commits[1].change_id) - - # Now do a real run - with self.stage('real run'): - with terminal.capture(): - yield cser - - series = patchstream.get_metadata_for_list('first', self.gitdir, 2) - self.assertEqual(2, len(series.commits)) - self.assertTrue(series.commits[0].change_id) - self.assertTrue(series.commits[1].change_id) - - # Try to mark again, which should fail - with self.stage('mark twice'): - with terminal.capture(): - with self.assertRaises(ValueError) as exc: - cser.mark('first', dry_run=False) - self.assertEqual('Marked commits 2/2', str(exc.exception)) - - # Use the --marked flag to make it succeed - with self.stage('mark twice with --marked'): - with terminal.capture(): - yield cser - self.assertEqual('Marked commits 2/2', str(exc.exception)) - - series2 = patchstream.get_metadata_for_list('first', self.gitdir, - 2) - self.assertEqual(2, len(series2.commits)) - self.assertEqual(series.commits[0].change_id, - series2.commits[0].change_id) - self.assertEqual(series.commits[1].change_id, - series2.commits[1].change_id) - - yield None - - def test_series_mark(self): - """Test marking a cseries, i.e. adding Change-Id fields""" - cor = self.check_series_mark() - cser = next(cor) - - # Start with a dry run, which should do nothing - cser = next(cor) - cser.mark('first', dry_run=True) - - # Now do a real run - cser = next(cor) - cser.mark('first', dry_run=False) - - # Try to mark again, which should fail - with terminal.capture(): - with self.assertRaises(ValueError) as exc: - cser.mark('first', dry_run=False) - self.assertEqual('Marked commits 2/2', str(exc.exception)) - - # Use the --allow-marked flag to make it succeed - cser = next(cor) - cser.mark('first', allow_marked=True, dry_run=False) - - self.assertFalse(next(cor)) - - def test_series_mark_cmdline(self): - """Test marking a cseries, i.e. adding Change-Id fields""" - cor = self.check_series_mark() - next(cor) - - # Start with a dry run, which should do nothing - next(cor) - self.run_args('series', '-n', '-s', 'first', 'mark', pwork=True) - - # Now do a real run - next(cor) - self.run_args('series', '-s', 'first', 'mark', pwork=True) - - # Try to mark again, which should fail - with terminal.capture() as (out, _): - self.run_args('series', '-s', 'first', 'mark', expect_ret=1, - pwork=True) - self.assertIn('Marked commits 2/2', out.getvalue()) - - # Use the --allow-marked flag to make it succeed - next(cor) - self.run_args('series', '-s', 'first', 'mark', '--allow-marked', - pwork=True) - self.assertFalse(next(cor)) - - def test_series_remove(self): - """Test removing a series""" - cser = self.get_cser() - - with self.stage('remove non-existent series'): - with self.assertRaises(ValueError) as exc: - cser.remove('first') - self.assertEqual("No such series 'first'", str(exc.exception)) - - with self.stage('add'): - with terminal.capture() as (out, _): - cser.add('first', '', mark=True) - self.assertTrue(cser.db.series_get_dict()) - pclist = cser.get_pcommit_dict() - self.assertEqual(2, len(pclist)) - - with self.stage('remove'): - with terminal.capture() as (out, _): - cser.remove('first') - self.assertEqual("Removed series 'first'", out.getvalue().strip()) - self.assertFalse(cser.db.series_get_dict()) - - pclist = cser.get_pcommit_dict() - self.assertFalse(len(pclist)) - - def test_series_remove_cmdline(self): - """Test removing a series using the command line""" - cser = self.get_cser() - - with self.stage('remove non-existent series'): - with terminal.capture() as (out, _): - self.run_args('series', '-s', 'first', 'rm', expect_ret=1, - pwork=True) - self.assertEqual("patman: ValueError: No such series 'first'", - out.getvalue().strip()) - - with self.stage('add'): - with terminal.capture() as (out, _): - cser.add('first', '', mark=True) - self.assertTrue(cser.db.series_get_dict()) - - with self.stage('remove'): - with terminal.capture() as (out, _): - cser.remove('first') - self.assertEqual("Removed series 'first'", out.getvalue().strip()) - self.assertFalse(cser.db.series_get_dict()) - - def check_series_remove_multiple(self): - """Check for removing a series with more than one version""" - cser = self.get_cser() - - with self.stage('setup'): - self.add_first2(True) - - with terminal.capture() as (out, _): - cser.add(None, '', mark=True) - cser.add('first', '', mark=True) - self.assertTrue(cser.db.series_get_dict()) - pclist = cser.get_pcommit_dict() - self.assertEqual(4, len(pclist)) - - # Do a dry-run removal - with self.stage('dry run'): - with terminal.capture() as (out, _): - yield cser - self.assertEqual("Removed version 1 from series 'first'\n" - 'Dry run completed', out.getvalue().strip()) - self.assertEqual({'first'}, cser.db.series_get_dict().keys()) - - svlist = cser.get_ser_ver_list() - self.assertEqual(2, len(svlist)) - self.assertEqual(1, svlist[0].idnum) - self.assertEqual(1, svlist[0].series_id) - self.assertEqual(2, svlist[0].version) - - self.assertEqual(2, svlist[1].idnum) - self.assertEqual(1, svlist[1].series_id) - self.assertEqual(1, svlist[1].version) - - # Now remove for real - with self.stage('real'): - with terminal.capture() as (out, _): - yield cser - self.assertEqual("Removed version 1 from series 'first'", - out.getvalue().strip()) - self.assertEqual({'first'}, cser.db.series_get_dict().keys()) - plist = cser.get_ser_ver_list() - self.assertEqual(1, len(plist)) - pclist = cser.get_pcommit_dict() - self.assertEqual(2, len(pclist)) - - with self.stage('remove only version'): - yield cser - self.assertEqual({'first'}, cser.db.series_get_dict().keys()) - - svlist = cser.get_ser_ver_list() - self.assertEqual(1, len(svlist)) - self.assertEqual(1, svlist[0].idnum) - self.assertEqual(1, svlist[0].series_id) - self.assertEqual(2, svlist[0].version) - - with self.stage('remove series (dry run'): - with terminal.capture() as (out, _): - yield cser - self.assertEqual("Removed series 'first'\nDry run completed", - out.getvalue().strip()) - self.assertTrue(cser.db.series_get_dict()) - self.assertTrue(cser.get_ser_ver_list()) - - with self.stage('remove series'): - with terminal.capture() as (out, _): - yield cser - self.assertEqual("Removed series 'first'", out.getvalue().strip()) - self.assertFalse(cser.db.series_get_dict()) - self.assertFalse(cser.get_ser_ver_list()) - - yield False - - def test_series_remove_multiple(self): - """Test removing a series with more than one version""" - cor = self.check_series_remove_multiple() - cser = next(cor) - - # Do a dry-run removal - cser.version_remove('first', 1, dry_run=True) - cser = next(cor) - - # Now remove for real - cser.version_remove('first', 1) - cser = next(cor) - - # Remove only version - with self.assertRaises(ValueError) as exc: - cser.version_remove('first', 2, dry_run=True) - self.assertEqual( - "Series 'first' only has one version: remove the series", - str(exc.exception)) - cser = next(cor) - - # Remove series (dry run) - cser.remove('first', dry_run=True) - cser = next(cor) - - # Remove series (real) - cser.remove('first') - - self.assertFalse(next(cor)) - cor.close() - - def test_series_remove_multiple_cmdline(self): - """Test removing a series with more than one version on cmdline""" - cor = self.check_series_remove_multiple() - next(cor) - - # Do a dry-run removal - self.run_args('series', '-n', '-s', 'first', '-V', '1', 'rm-version', - pwork=True) - next(cor) - - # Now remove for real - self.run_args('series', '-s', 'first', '-V', '1', 'rm-version', - pwork=True) - next(cor) - - # Remove only version - with terminal.capture() as (out, _): - self.run_args('series', '-n', '-s', 'first', '-V', '2', - 'rm-version', expect_ret=1, pwork=True) - self.assertIn( - "Series 'first' only has one version: remove the series", - out.getvalue().strip()) - next(cor) - - # Remove series (dry run) - self.run_args('series', '-n', '-s', 'first', 'rm', pwork=True) - next(cor) - - # Remove series (real) - self.run_args('series', '-s', 'first', 'rm', pwork=True) - - self.assertFalse(next(cor)) - cor.close() - - def test_patchwork_set_project(self): - """Test setting the project ID""" - cser = self.get_cser() - pwork = Patchwork.for_testing(self._fake_patchwork_cser) - with terminal.capture() as (out, _): - cser.project_set(pwork, 'U-Boot') - self.assertEqual( - f"Project 'U-Boot' patchwork-ID {self.PROJ_ID} link-name uboot", - out.getvalue().strip()) - - def test_patchwork_project_get(self): - """Test setting the project ID""" - cser = self.get_cser() - pwork = Patchwork.for_testing(self._fake_patchwork_cser) - self.assertFalse(cser.project_get()) - with terminal.capture() as (out, _): - cser.project_set(pwork, 'U-Boot') - self.assertEqual( - f"Project 'U-Boot' patchwork-ID {self.PROJ_ID} link-name uboot", - out.getvalue().strip()) - - name, pwid, link_name = cser.project_get() - self.assertEqual('U-Boot', name) - self.assertEqual(self.PROJ_ID, pwid) - self.assertEqual('uboot', link_name) - - def test_patchwork_project_get_cmdline(self): - """Test setting the project ID""" - cser = self.get_cser() - - self.assertFalse(cser.project_get()) - - pwork = Patchwork.for_testing(self._fake_patchwork_cser) - with terminal.capture() as (out, _): - self.run_args('-P', 'https://url', 'patchwork', 'set-project', - 'U-Boot', pwork=pwork) - self.assertEqual( - f"Project 'U-Boot' patchwork-ID {self.PROJ_ID} link-name uboot", - out.getvalue().strip()) - - name, pwid, link_name = cser.project_get() - self.assertEqual('U-Boot', name) - self.assertEqual(6, pwid) - self.assertEqual('uboot', link_name) - - with terminal.capture() as (out, _): - self.run_args('-P', 'https://url', 'patchwork', 'get-project') - self.assertEqual( - f"Project 'U-Boot' patchwork-ID {self.PROJ_ID} link-name uboot", - out.getvalue().strip()) - - def check_series_list_patches(self): - """Test listing the patches for a series""" - cser = self.get_cser() - - with self.stage('setup'): - with terminal.capture() as (out, _): - cser.add(None, '', allow_unmarked=True) - cser.add('second', allow_unmarked=True) - target = self.repo.lookup_reference('refs/heads/second') - self.repo.checkout( - target, strategy=pygit2.enums.CheckoutStrategy.FORCE) - cser.increment('second') - - with self.stage('list first'): - with terminal.capture() as (out, _): - yield cser - itr = iter(out.getvalue().splitlines()) - self.assertEqual("Branch 'first' (total 2): 2:unknown", next(itr)) - self.assertIn('PatchId', next(itr)) - self.assertRegex(next(itr), r' 0 .* i2c: I2C things') - self.assertRegex(next(itr), r' 1 .* spi: SPI fixes') - - with self.stage('list second2'): - with terminal.capture() as (out, _): - yield cser - itr = iter(out.getvalue().splitlines()) - self.assertEqual( - "Branch 'second2' (total 3): 3:unknown", next(itr)) - self.assertIn('PatchId', next(itr)) - self.assertRegex( - next(itr), ' 0 .* video: Some video improvements') - self.assertRegex(next(itr), ' 1 .* serial: Add a serial driver') - self.assertRegex(next(itr), ' 2 .* bootm: Make it boot') - - yield None - - def test_series_list_patches(self): - """Test listing the patches for a series""" - cor = self.check_series_list_patches() - cser = next(cor) - - # list first - cser.list_patches('first', 1) - cser = next(cor) - - # list second2 - cser.list_patches('second2', 2) - self.assertFalse(next(cor)) - cor.close() - - def test_series_list_patches_cmdline(self): - """Test listing the patches for a series using the cmdline""" - cor = self.check_series_list_patches() - next(cor) - - # list first - self.run_args('series', '-s', 'first', 'patches', pwork=True) - next(cor) - - # list second2 - self.run_args('series', '-s', 'second', '-V', '2', 'patches', - pwork=True) - self.assertFalse(next(cor)) - cor.close() - - def test_series_list_patches_detail(self): - """Test listing the patches for a series""" - cser = self.get_cser() - with terminal.capture(): - cser.add(None, '', allow_unmarked=True) - cser.add('second', allow_unmarked=True) - target = self.repo.lookup_reference('refs/heads/second') - self.repo.checkout( - target, strategy=pygit2.enums.CheckoutStrategy.FORCE) - cser.increment('second') - - with terminal.capture() as (out, _): - cser.list_patches('first', 1, show_commit=True) - expect = r'''Branch 'first' (total 2): 2:unknown -Seq State Com PatchId Commit Subject - 0 unknown - .* i2c: I2C things - -commit .* -Author: Test user <[email protected]> -Date: .* - - i2c: I2C things - - This has some stuff to do with I2C - - i2c.c | 2 ++ - 1 file changed, 2 insertions(+) - - - 1 unknown - .* spi: SPI fixes - -commit .* -Author: Test user <[email protected]> -Date: .* - - spi: SPI fixes - - SPI needs some fixes - and here they are - - Signed-off-by: Lord Edmund Blackaddër <[email protected]> - - Series-to: u-boot - Commit-notes: - title of the series - This is the cover letter for the series - with various details - END - - spi.c | 3 +++ - 1 file changed, 3 insertions(+) -''' - itr = iter(out.getvalue().splitlines()) - for seq, eline in enumerate(expect.splitlines()): - line = next(itr).rstrip() - if '*' in eline: - self.assertRegex(line, eline, f'line {seq + 1}') - else: - self.assertEqual(eline, line, f'line {seq + 1}') - - # Show just the patch; this should exclude the commit message - with terminal.capture() as (out, _): - cser.list_patches('first', 1, show_patch=True) - chk = out.getvalue() - self.assertIn('SPI fixes', chk) # subject - self.assertNotIn('SPI needs some fixes', chk) # commit body - self.assertIn('make SPI work', chk) # patch body - - # Show both - with terminal.capture() as (out, _): - cser.list_patches('first', 1, show_commit=True, show_patch=True) - chk = out.getvalue() - self.assertIn('SPI fixes', chk) # subject - self.assertIn('SPI needs some fixes', chk) # commit body - self.assertIn('make SPI work', chk) # patch body - - def check_series_gather(self): - """Checker for gathering tags for a series""" - cser = self.get_cser() - with self.stage('setup'): - pwork = Patchwork.for_testing(self._fake_patchwork_cser) - self.assertFalse(cser.project_get()) - cser.project_set(pwork, 'U-Boot', quiet=True) - - with terminal.capture() as (out, _): - cser.add('second', 'description', allow_unmarked=True) - - ser = cser.get_series_by_name('second') - pwid = cser.get_series_svid(ser.idnum, 1) - - # First do a dry run - with self.stage('gather: dry run'): - with terminal.capture() as (out, _): - yield cser, pwork - lines = out.getvalue().splitlines() - self.assertEqual( - f"Updating series 'second' version 1 from link " - f"'{self.SERIES_ID_SECOND_V1}'", - lines[0]) - self.assertEqual('3 patches updated (7 requests)', lines[1]) - self.assertEqual('Dry run completed', lines[2]) - self.assertEqual(3, len(lines)) - - pwc = cser.get_pcommit_dict(pwid) - self.assertIsNone(pwc[0].state) - self.assertIsNone(pwc[1].state) - self.assertIsNone(pwc[2].state) - - # Now try it again, gathering tags - with self.stage('gather: dry run'): - with terminal.capture() as (out, _): - yield cser, pwork - lines = out.getvalue().splitlines() - itr = iter(lines) - self.assertEqual( - f"Updating series 'second' version 1 from link " - f"'{self.SERIES_ID_SECOND_V1}'", - next(itr)) - self.assertEqual(' 1 video: Some video improvements', next(itr)) - self.assertEqual(' + Reviewed-by: Fred Bloggs <[email protected]>', - next(itr)) - self.assertEqual(' 2 serial: Add a serial driver', next(itr)) - self.assertEqual(' 3 bootm: Make it boot', next(itr)) - - self.assertRegex( - next(itr), 'Checking out upstream commit refs/heads/base: .*') - self.assertEqual("Processing 3 commits from branch 'second'", - next(itr)) - self.assertRegex( - next(itr), - f'- added 1 tag: {HASH_RE} as {HASH_RE} ' - 'video: Some video improvements') - self.assertRegex( - next(itr), - f"- upd links '1:456': {HASH_RE} as {HASH_RE} " - 'serial: Add a serial driver') - self.assertRegex( - next(itr), - f'- {HASH_RE} as {HASH_RE} ' - 'bootm: Make it boot') - self.assertRegex( - next(itr), - f'Updating branch second from {HASH_RE} to {HASH_RE}') - self.assertEqual('3 patches updated (7 requests)', next(itr)) - self.assertEqual('Dry run completed', next(itr)) - self.assert_finished(itr) - - # Make sure that no tags were added to the branch - series = patchstream.get_metadata_for_list('second', self.gitdir, - 3) - for cmt in series.commits: - self.assertFalse(cmt.rtags, - 'Commit {cmt.subject} rtags {cmt.rtags}') - - # Now do it for real - with self.stage('gather: real'): - with terminal.capture() as (out, _): - yield cser, pwork - lines2 = out.getvalue().splitlines() - self.assertEqual(lines2, lines[:-1]) - - # Make sure that the tags were added to the branch - series = patchstream.get_metadata_for_list('second', self.gitdir, - 3) - self.assertEqual( - {'Reviewed-by': {'Fred Bloggs <[email protected]>'}}, - series.commits[0].rtags) - self.assertFalse(series.commits[1].rtags) - self.assertFalse(series.commits[2].rtags) - - # Make sure the status was updated - pwc = cser.get_pcommit_dict(pwid) - self.assertEqual('accepted', pwc[0].state) - self.assertEqual('changes-requested', pwc[1].state) - self.assertEqual('rejected', pwc[2].state) - - yield None - - def test_series_gather(self): - """Test gathering tags for a series""" - cor = self.check_series_gather() - cser, pwork = next(cor) - - # sync (dry_run) - cser.gather(pwork, 'second', None, False, False, False, dry_run=True) - cser, pwork = next(cor) - - # gather (dry_run) - cser.gather(pwork, 'second', None, False, False, True, dry_run=True) - cser, pwork = next(cor) - - # gather (real) - cser.gather(pwork, 'second', None, False, False, True) - - self.assertFalse(next(cor)) - - def test_series_gather_cmdline(self): - """Test gathering tags for a series with cmdline""" - cor = self.check_series_gather() - _, pwork = next(cor) - - # sync (dry_run) - self.run_args( - 'series', '-n', '-s', 'second', 'gather', '-G', pwork=pwork) - - # gather (dry_run) - _, pwork = next(cor) - self.run_args('series', '-n', '-s', 'second', 'gather', pwork=pwork) - - # gather (real) - _, pwork = next(cor) - self.run_args('series', '-s', 'second', 'gather', pwork=pwork) - - self.assertFalse(next(cor)) - - def check_series_gather_all(self): - """Gather all series at once""" - with self.stage('setup'): - cser, pwork = self.setup_second(False) - - with terminal.capture(): - cser.add('first', 'description', allow_unmarked=True) - cser.increment('first') - cser.increment('first') - cser.link_set('first', 1, '123', True) - cser.link_set('first', 2, '1234', True) - cser.link_set('first', 3, f'{self.SERIES_ID_FIRST_V3}', True) - cser.link_auto(pwork, 'second', 2, True) - - with self.stage('no options'): - with terminal.capture() as (out, _): - yield cser, pwork - self.assertEqual( - "Syncing 'first' v3\n" - "Syncing 'second' v2\n" - '\n' - '5 patches and 2 cover letters updated, 0 missing links ' - '(14 requests)\n' - 'Dry run completed', - out.getvalue().strip()) - - with self.stage('gather'): - with terminal.capture() as (out, _): - yield cser, pwork - lines = out.getvalue().splitlines() - itr = iter(lines) - self.assertEqual("Syncing 'first' v3", next(itr)) - self.assertEqual(' 1 i2c: I2C things', next(itr)) - self.assertEqual( - ' + Tested-by: Mary Smith <[email protected]> # yak', - next(itr)) - self.assertEqual(' 2 spi: SPI fixes', next(itr)) - self.assertRegex( - next(itr), 'Checking out upstream commit refs/heads/base: .*') - self.assertEqual( - "Processing 2 commits from branch 'first3'", next(itr)) - self.assertRegex( - next(itr), - f'- added 1 tag: {HASH_RE} as {HASH_RE} i2c: I2C things') - self.assertRegex( - next(itr), - f"- upd links '3:31': {HASH_RE} as {HASH_RE} spi: SPI fixes") - self.assertRegex( - next(itr), - f'Updating branch first3 from {HASH_RE} to {HASH_RE}') - self.assertEqual('', next(itr)) - - self.assertEqual("Syncing 'second' v2", next(itr)) - self.assertEqual(' 1 video: Some video improvements', next(itr)) - self.assertEqual( - ' + Reviewed-by: Fred Bloggs <[email protected]>', next(itr)) - self.assertEqual(' 2 serial: Add a serial driver', next(itr)) - self.assertEqual(' 3 bootm: Make it boot', next(itr)) - self.assertRegex( - next(itr), 'Checking out upstream commit refs/heads/base: .*') - self.assertEqual( - "Processing 3 commits from branch 'second2'", next(itr)) - self.assertRegex( - next(itr), - f'- added 1 tag: {HASH_RE} as {HASH_RE} ' - 'video: Some video improvements') - self.assertRegex( - next(itr), - f"- upd links '2:457 1:456': {HASH_RE} as {HASH_RE} " - 'serial: Add a serial driver') - self.assertRegex( - next(itr), - f'- {HASH_RE} as {HASH_RE} ' - 'bootm: Make it boot') - self.assertRegex( - next(itr), - f'Updating branch second2 from {HASH_RE} to {HASH_RE}') - self.assertEqual('', next(itr)) - self.assertEqual( - '5 patches and 2 cover letters updated, 0 missing links ' - '(14 requests)', - next(itr)) - self.assertEqual('Dry run completed', next(itr)) - self.assert_finished(itr) - - with self.stage('gather, patch comments,!dry_run'): - with terminal.capture() as (out, _): - yield cser, pwork - lines = out.getvalue().splitlines() - itr = iter(lines) - self.assertEqual("Syncing 'first' v1", next(itr)) - self.assertEqual(' 1 i2c: I2C things', next(itr)) - self.assertEqual( - ' + Tested-by: Mary Smith <[email protected]> # yak', - next(itr)) - self.assertEqual(' 2 spi: SPI fixes', next(itr)) - self.assertRegex( - next(itr), 'Checking out upstream commit refs/heads/base: .*') - self.assertEqual( - "Processing 2 commits from branch 'first'", next(itr)) - self.assertRegex( - next(itr), - f'- added 1 tag: {HASH_RE} as {HASH_RE} i2c: I2C things') - self.assertRegex( - next(itr), - f"- upd links '1:123': {HASH_RE} as {HASH_RE} spi: SPI fixes") - self.assertRegex( - next(itr), - f'Updating branch first from {HASH_RE} to {HASH_RE}') - self.assertEqual('', next(itr)) - - self.assertEqual("Syncing 'first' v2", next(itr)) - self.assertEqual(' 1 i2c: I2C things', next(itr)) - self.assertEqual( - ' + Tested-by: Mary Smith <[email protected]> # yak', - next(itr)) - self.assertEqual(' 2 spi: SPI fixes', next(itr)) - self.assertRegex( - next(itr), 'Checking out upstream commit refs/heads/base: .*') - self.assertEqual( - "Processing 2 commits from branch 'first2'", next(itr)) - self.assertRegex( - next(itr), - f'- added 1 tag: {HASH_RE} as {HASH_RE} ' - 'i2c: I2C things') - self.assertRegex( - next(itr), - f"- upd links '2:1234': {HASH_RE} as {HASH_RE} spi: SPI fixes") - self.assertRegex( - next(itr), - f'Updating branch first2 from {HASH_RE} to {HASH_RE}') - self.assertEqual('', next(itr)) - self.assertEqual("Syncing 'first' v3", next(itr)) - self.assertEqual(' 1 i2c: I2C things', next(itr)) - self.assertEqual( - ' + Tested-by: Mary Smith <[email protected]> # yak', - next(itr)) - self.assertEqual(' 2 spi: SPI fixes', next(itr)) - self.assertRegex( - next(itr), 'Checking out upstream commit refs/heads/base: .*') - self.assertEqual( - "Processing 2 commits from branch 'first3'", next(itr)) - self.assertRegex( - next(itr), - f'- added 1 tag: {HASH_RE} as {HASH_RE} i2c: I2C things') - self.assertRegex( - next(itr), - f"- upd links '3:31': {HASH_RE} as {HASH_RE} spi: SPI fixes") - self.assertRegex( - next(itr), - f'Updating branch first3 from {HASH_RE} to {HASH_RE}') - self.assertEqual('', next(itr)) - - self.assertEqual("Syncing 'second' v1", next(itr)) - self.assertEqual(' 1 video: Some video improvements', next(itr)) - self.assertEqual( - ' + Reviewed-by: Fred Bloggs <[email protected]>', next(itr)) - self.assertEqual( - 'Review: Fred Bloggs <[email protected]>', next(itr)) - self.assertEqual(' > This was my original patch', next(itr)) - self.assertEqual(' > which is being quoted', next(itr)) - self.assertEqual( - ' I like the approach here and I would love to see more ' - 'of it.', next(itr)) - self.assertEqual('', next(itr)) - self.assertEqual(' 2 serial: Add a serial driver', next(itr)) - self.assertEqual(' 3 bootm: Make it boot', next(itr)) - self.assertRegex( - next(itr), 'Checking out upstream commit refs/heads/base: .*') - self.assertEqual( - "Processing 3 commits from branch 'second'", next(itr)) - self.assertRegex( - next(itr), - f'- added 1 tag: {HASH_RE} as {HASH_RE} ' - 'video: Some video improvements') - self.assertRegex( - next(itr), - f"- upd links '1:456': {HASH_RE} as {HASH_RE} " - 'serial: Add a serial driver') - self.assertRegex( - next(itr), - f'- {HASH_RE} as {HASH_RE} ' - 'bootm: Make it boot') - self.assertRegex( - next(itr), - f'Updating branch second from {HASH_RE} to {HASH_RE}') - self.assertEqual('', next(itr)) - - self.assertEqual("Syncing 'second' v2", next(itr)) - self.assertEqual(' 1 video: Some video improvements', next(itr)) - self.assertEqual( - ' + Reviewed-by: Fred Bloggs <[email protected]>', next(itr)) - self.assertEqual( - 'Review: Fred Bloggs <[email protected]>', next(itr)) - self.assertEqual(' > This was my original patch', next(itr)) - self.assertEqual(' > which is being quoted', next(itr)) - self.assertEqual( - ' I like the approach here and I would love to see more ' - 'of it.', next(itr)) - self.assertEqual('', next(itr)) - self.assertEqual(' 2 serial: Add a serial driver', next(itr)) - self.assertEqual(' 3 bootm: Make it boot', next(itr)) - self.assertRegex( - next(itr), 'Checking out upstream commit refs/heads/base: .*') - self.assertEqual( - "Processing 3 commits from branch 'second2'", next(itr)) - self.assertRegex( - next(itr), - f'- added 1 tag: {HASH_RE} as {HASH_RE} ' - 'video: Some video improvements') - self.assertRegex( - next(itr), - f"- upd links '2:457 1:456': {HASH_RE} as {HASH_RE} " - 'serial: Add a serial driver') - self.assertRegex( - next(itr), - f'- {HASH_RE} as {HASH_RE} ' - 'bootm: Make it boot') - self.assertRegex( - next(itr), - f'Updating branch second2 from {HASH_RE} to {HASH_RE}') - self.assertEqual('', next(itr)) - self.assertEqual( - '12 patches and 3 cover letters updated, 0 missing links ' - '(32 requests)', next(itr)) - self.assert_finished(itr) - - yield None - - def test_series_gather_all(self): - """Gather all series at once""" - cor = self.check_series_gather_all() - cser, pwork = next(cor) - - # no options - cser.gather_all(pwork, False, True, False, False, dry_run=True) - cser, pwork = next(cor) - - # gather - cser.gather_all(pwork, False, False, False, True, dry_run=True) - cser, pwork = next(cor) - - # gather, patch comments, !dry_run - cser.gather_all(pwork, True, False, True, True) - - self.assertFalse(next(cor)) - - def test_series_gather_all_cmdline(self): - """Sync all series at once using cmdline""" - cor = self.check_series_gather_all() - _, pwork = next(cor) - - # no options - self.run_args('series', '-n', '-s', 'second', 'gather-all', '-G', - pwork=pwork) - _, pwork = next(cor) - - # gather - self.run_args('series', '-n', '-s', 'second', 'gather-all', - pwork=pwork) - _, pwork = next(cor) - - # gather, patch comments, !dry_run - self.run_args('series', '-s', 'second', 'gather-all', '-a', '-c', - pwork=pwork) - - self.assertFalse(next(cor)) - - def _check_second(self, itr, show_all): - """Check output from a 'progress' command - - Args: - itr (Iterator): Contains the output lines to check - show_all (bool): True if all versions are being shown, not just - latest - """ - self.assertEqual('second: Series for my board (versions: 1 2)', - next(itr)) - if show_all: - self.assertEqual("Branch 'second' (total 3): 3:unknown", - next(itr)) - self.assertIn('PatchId', next(itr)) - self.assertRegex( - next(itr), - ' 0 unknown - .* video: Some video improvements') - self.assertRegex( - next(itr), - ' 1 unknown - .* serial: Add a serial driver') - self.assertRegex( - next(itr), - ' 2 unknown - .* bootm: Make it boot') - self.assertEqual('', next(itr)) - self.assertEqual( - "Branch 'second2' (total 3): 1:accepted 1:changes 1:rejected", - next(itr)) - self.assertIn('PatchId', next(itr)) - self.assertEqual( - 'Cov 2 139 ' - 'The name of the cover letter', next(itr)) - self.assertRegex( - next(itr), - ' 0 accepted 2 110 .* video: Some video improvements') - self.assertRegex( - next(itr), - ' 1 changes 111 .* serial: Add a serial driver') - self.assertRegex( - next(itr), - ' 2 rejected 3 112 .* bootm: Make it boot') - - def test_series_progress(self): - """Test showing progress for a cseries""" - self.setup_second() - self.db_close() - - with self.stage('latest versions'): - args = Namespace(subcmd='progress', series='second', - show_all_versions=False, list_patches=True) - with terminal.capture() as (out, _): - control.do_series(args, test_db=self.tmpdir, pwork=True) - lines = iter(out.getvalue().splitlines()) - self._check_second(lines, False) - - with self.stage('all versions'): - args.show_all_versions = True - with terminal.capture() as (out, _): - control.do_series(args, test_db=self.tmpdir, pwork=True) - lines = iter(out.getvalue().splitlines()) - self._check_second(lines, True) - - def _check_first(self, itr): - """Check output from the progress command - - Args: - itr (Iterator): Contains the output lines to check - """ - self.assertEqual('first: (versions: 1)', next(itr)) - self.assertEqual("Branch 'first' (total 2): 2:unknown", next(itr)) - self.assertIn('PatchId', next(itr)) - self.assertRegex( - next(itr), - ' 0 unknown - .* i2c: I2C things') - self.assertRegex( - next(itr), - ' 1 unknown - .* spi: SPI fixes') - self.assertEqual('', next(itr)) - - def test_series_progress_all(self): - """Test showing progress for all cseries""" - self.setup_second() - self.db_close() - - with self.stage('progress with patches'): - args = Namespace(subcmd='progress', series=None, - show_all_versions=False, list_patches=True) - with terminal.capture() as (out, _): - control.do_series(args, test_db=self.tmpdir, pwork=True) - lines = iter(out.getvalue().splitlines()) - self._check_first(lines) - self._check_second(lines, False) - - with self.stage('all versions'): - args.show_all_versions = True - with terminal.capture() as (out, _): - control.do_series(args, test_db=self.tmpdir, pwork=True) - lines = iter(out.getvalue().splitlines()) - self._check_first(lines) - self._check_second(lines, True) - - def test_series_progress_no_patches(self): - """Test showing progress for all cseries without patches""" - self.setup_second() - - with terminal.capture() as (out, _): - self.run_args('series', 'progress', pwork=True) - itr = iter(out.getvalue().splitlines()) - self.assertEqual( - 'Name Description ' - 'Count Status', next(itr)) - self.assertTrue(next(itr).startswith('--')) - self.assertEqual( - 'first ' - ' 2 2:unknown', next(itr)) - self.assertEqual( - 'second2 The name of the cover letter ' - ' 3 1:accepted 1:changes 1:rejected', next(itr)) - self.assertTrue(next(itr).startswith('--')) - self.assertEqual( - ['2', 'series', '5', '2:unknown', '1:accepted', '1:changes', - '1:rejected'], - next(itr).split()) - self.assert_finished(itr) - - def test_series_progress_all_no_patches(self): - """Test showing progress for all cseries versions without patches""" - self.setup_second() - - with terminal.capture() as (out, _): - self.run_args('series', 'progress', '--show-all-versions', - pwork=True) - itr = iter(out.getvalue().splitlines()) - self.assertEqual( - 'Name Description ' - 'Count Status', next(itr)) - self.assertTrue(next(itr).startswith('--')) - self.assertEqual( - 'first ' - ' 2 2:unknown', next(itr)) - self.assertEqual( - 'second Series for my board ' - ' 3 3:unknown', next(itr)) - self.assertEqual( - 'second2 The name of the cover letter ' - ' 3 1:accepted 1:changes 1:rejected', next(itr)) - self.assertTrue(next(itr).startswith('--')) - self.assertEqual( - ['3', 'series', '8', '5:unknown', '1:accepted', '1:changes', - '1:rejected'], - next(itr).split()) - self.assert_finished(itr) - - def test_series_summary(self): - """Test showing a summary of series status""" - self.setup_second() - - self.db_close() - args = Namespace(subcmd='summary', series=None) - with terminal.capture() as (out, _): - control.do_series(args, test_db=self.tmpdir, pwork=True) - lines = out.getvalue().splitlines() - self.assertEqual( - 'Name Status Description', - lines[0]) - self.assertEqual( - '----------------- ------ ------------------------------', - lines[1]) - self.assertEqual('first -/2 ', lines[2]) - self.assertEqual('second 1/3 Series for my board', lines[3]) - - def test_series_open(self): - """Test opening a series in a web browser""" - cser = self.get_cser() - pwork = Patchwork.for_testing(self._fake_patchwork_cser) - self.assertFalse(cser.project_get()) - pwork.project_set(self.PROJ_ID, self.PROJ_LINK_NAME) - - with terminal.capture(): - cser.add('second', allow_unmarked=True) - cser.increment('second') - cser.link_auto(pwork, 'second', 2, True) - cser.gather(pwork, 'second', 2, False, False, False) - - with mock.patch.object(cros_subprocess.Popen, '__init__', - return_value=None) as method: - with terminal.capture() as (out, _): - cser.open(pwork, 'second2', 2) - - url = ('https://patchwork.ozlabs.org/project/uboot/list/?series=457' - '&state=*&archive=both') - method.assert_called_once_with(['xdg-open', url]) - self.assertEqual(f'Opening {url}', out.getvalue().strip()) - - def test_name_version(self): - """Test handling of series names and versions""" - cser = self.get_cser() - repo = self.repo - - self.assertEqual(('fred', None), - cser_helper.split_name_version('fred')) - self.assertEqual(('mary', 2), cser_helper.split_name_version('mary2')) - - ser, version = cser._parse_series_and_version(None, None) - self.assertEqual('first', ser.name) - self.assertEqual(1, version) - - ser, version = cser._parse_series_and_version('first', None) - self.assertEqual('first', ser.name) - self.assertEqual(1, version) - - ser, version = cser._parse_series_and_version('first', 2) - self.assertEqual('first', ser.name) - self.assertEqual(2, version) - - with self.assertRaises(ValueError) as exc: - cser._parse_series_and_version('123', 2) - self.assertEqual( - "Series name '123' cannot be a number, use '<name><version>'", - str(exc.exception)) - - with self.assertRaises(ValueError) as exc: - cser._parse_series_and_version('first', 100) - self.assertEqual("Version 100 exceeds 99", str(exc.exception)) - - with terminal.capture() as (_, err): - cser._parse_series_and_version('mary3', 4) - self.assertIn('Version mismatch: -V has 4 but branch name indicates 3', - err.getvalue()) - - ser, version = cser._parse_series_and_version('mary', 4) - self.assertEqual('mary', ser.name) - self.assertEqual(4, version) - - # Move off the branch and check for a sensible error - commit = repo.revparse_single('first~') - repo.checkout_tree(commit) - repo.set_head(commit.oid) - - with self.assertRaises(ValueError) as exc: - cser._parse_series_and_version(None, None) - self.assertEqual('No branch detected: please use -s <series>', - str(exc.exception)) - - def test_name_version_extra(self): - """More tests for some corner cases""" - cser, _ = self.setup_second() - target = self.repo.lookup_reference('refs/heads/second2') - self.repo.checkout( - target, strategy=pygit2.enums.CheckoutStrategy.FORCE) - - ser, version = cser._parse_series_and_version(None, None) - self.assertEqual('second', ser.name) - self.assertEqual(2, version) - - ser, version = cser._parse_series_and_version('second2', None) - self.assertEqual('second', ser.name) - self.assertEqual(2, version) - - def test_migrate(self): - """Test migration to later schema versions""" - db = database.Database(f'{self.tmpdir}/.patman.db') - with terminal.capture() as (out, err): - db.open_it() - self.assertEqual( - f'Creating new database {self.tmpdir}/.patman.db', - err.getvalue().strip()) - - self.assertEqual(0, db.get_schema_version()) - - for version in range(1, database.LATEST + 1): - with terminal.capture() as (out, _): - db.migrate_to(version) - self.assertTrue(os.path.exists( - f'{self.tmpdir}/.patman.dbold.v{version - 1}')) - self.assertEqual(f'Update database to v{version}', - out.getvalue().strip()) - self.assertEqual(version, db.get_schema_version()) - self.assertEqual(4, database.LATEST) - - def test_series_scan(self): - """Test scanning a series for updates""" - cser, _ = self.setup_second() - target = self.repo.lookup_reference('refs/heads/second2') - self.repo.checkout( - target, strategy=pygit2.enums.CheckoutStrategy.FORCE) - - # Add a new commit - self.repo = pygit2.init_repository(self.gitdir) - self.make_commit_with_file( - 'wip: Try out a new thing', 'Just checking', 'wibble.c', - '''changes to wibble''') - target = self.repo.revparse_single('HEAD') - self.repo.reset(target.oid, pygit2.enums.ResetMode.HARD) - - # name = gitutil.get_branch(self.gitdir) - # upstream_name = gitutil.get_upstream(self.gitdir, name) - name, ser, version, _ = cser.prep_series(None) - - # We now have 4 commits numbered 0 (second~3) to 3 (the one we just - # added). Drop commit 1 (the 'serial' one) from the branch - cser._filter_commits(name, ser, 1) - svid = cser.get_ser_ver(ser.idnum, version).idnum - old_pcdict = cser.get_pcommit_dict(svid).values() - - expect = '''Syncing series 'second2' v2: mark False allow_unmarked True - 0 video: Some video improvements -- 1 serial: Add a serial driver - 1 bootm: Make it boot -+ 2 Just checking -''' - with terminal.capture() as (out, _): - self.run_args('series', '-n', 'scan', '-M', pwork=True) - self.assertEqual(expect + 'Dry run completed\n', out.getvalue()) - - new_pcdict = cser.get_pcommit_dict(svid).values() - self.assertEqual(list(old_pcdict), list(new_pcdict)) - - with terminal.capture() as (out, _): - self.run_args('series', 'scan', '-M', pwork=True) - self.assertEqual(expect, out.getvalue()) - - new_pcdict = cser.get_pcommit_dict(svid).values() - self.assertEqual(len(old_pcdict), len(new_pcdict)) - chk = list(new_pcdict) - self.assertNotEqual(list(old_pcdict), list(new_pcdict)) - self.assertEqual('video: Some video improvements', chk[0].subject) - self.assertEqual('bootm: Make it boot', chk[1].subject) - self.assertEqual('Just checking', chk[2].subject) - - def test_series_send(self): - """Test sending a series""" - cser, pwork = self.setup_second() - - # Create a third version - with terminal.capture(): - cser.increment('second') - series = patchstream.get_metadata_for_list('second3', self.gitdir, 3) - self.assertEqual('2:457 1:456', series.links) - self.assertEqual('3', series.version) - - with terminal.capture() as (out, err): - self.run_args('series', '-n', '-s', 'second3', 'send', - '--no-autolink', pwork=pwork) - self.assertIn('Send a total of 3 patches with a cover letter', - out.getvalue()) - self.assertIn( - 'video.c:1: warning: Missing or malformed SPDX-License-Identifier ' - 'tag in line 1', err.getvalue()) - self.assertIn( - '<patch>:19: warning: added, moved or deleted file(s), does ' - 'MAINTAINERS need updating?', err.getvalue()) - self.assertIn('bootm.c:1: check: Avoid CamelCase: <Fix>', - err.getvalue()) - self.assertIn( - 'Cc: Anatolij Gustschin <[email protected]>', out.getvalue()) - - self.assertTrue(os.path.exists(os.path.join( - self.tmpdir, '0001-video-Some-video-improvements.patch'))) - self.assertTrue(os.path.exists(os.path.join( - self.tmpdir, '0002-serial-Add-a-serial-driver.patch'))) - self.assertTrue(os.path.exists(os.path.join( - self.tmpdir, '0003-bootm-Make-it-boot.patch'))) - - def test_series_send_and_link(self): - """Test sending a series and then adding its link to the database""" - def h_sleep(time_s): - if cser.get_time() > 25: - self.autolink_extra = {'id': 500, - 'name': 'Series for my board', - 'version': 3} - cser.inc_fake_time(time_s) - - cser, pwork = self.setup_second() - - # Create a third version - with terminal.capture(): - cser.increment('second') - series = patchstream.get_metadata_for_list('second3', self.gitdir, 3) - self.assertEqual('2:457 1:456', series.links) - self.assertEqual('3', series.version) - - with terminal.capture(): - self.run_args('series', '-n', 'send', pwork=pwork) - - cser.set_fake_time(h_sleep) - with terminal.capture() as (out, _): - cser.link_auto(pwork, 'second3', 3, True, 50) - itr = iter(out.getvalue().splitlines()) - for i in range(7): - self.assertEqual( - "Possible matches for 'second' v3 desc 'Series for my board':", - next(itr), f'failed at i={i}') - self.assertEqual(' Link Version Description', next(itr)) - self.assertEqual(' 456 1 Series for my board', next(itr)) - self.assertEqual(' 457 2 Series for my board', next(itr)) - self.assertEqual('Sleeping for 5 seconds', next(itr)) - self.assertEqual('Link completed after 35 seconds', next(itr)) - self.assertRegex( - next(itr), 'Checking out upstream commit refs/heads/base: .*') - self.assertEqual( - "Processing 3 commits from branch 'second3'", next(itr)) - self.assertRegex( - next(itr), - f'- {HASH_RE} as {HASH_RE} ' - 'video: Some video improvements') - self.assertRegex( - next(itr), - f"- add links '3:500 2:457 1:456': {HASH_RE} as {HASH_RE} " - 'serial: Add a serial driver') - self.assertRegex( - next(itr), - f'- add v3: {HASH_RE} as {HASH_RE} ' - 'bootm: Make it boot') - self.assertRegex( - next(itr), - f'Updating branch second3 from {HASH_RE} to {HASH_RE}') - self.assertEqual( - "Setting link for series 'second' v3 to 500", next(itr)) - - def _check_status(self, out, has_comments, has_cover_comments): - """Check output from the status command - - Args: - itr (Iterator): Contains the output lines to check - """ - itr = iter(out.getvalue().splitlines()) - if has_cover_comments: - self.assertEqual('Cov The name of the cover letter', next(itr)) - self.assertEqual( - 'From: A user <[email protected]>: Sun 13 Apr 14:06:02 MDT 2025', - next(itr)) - self.assertEqual('some comment', next(itr)) - self.assertEqual('', next(itr)) - - self.assertEqual( - 'From: Ghenkis Khan <[email protected]>: Sun 13 Apr 13:06:02 ' - 'MDT 2025', - next(itr)) - self.assertEqual('another comment', next(itr)) - self.assertEqual('', next(itr)) - - self.assertEqual(' 1 video: Some video improvements', next(itr)) - self.assertEqual(' + Reviewed-by: Fred Bloggs <[email protected]>', - next(itr)) - if has_comments: - self.assertEqual( - 'Review: Fred Bloggs <[email protected]>', next(itr)) - self.assertEqual(' > This was my original patch', next(itr)) - self.assertEqual(' > which is being quoted', next(itr)) - self.assertEqual( - ' I like the approach here and I would love to see more ' - 'of it.', next(itr)) - self.assertEqual('', next(itr)) - - self.assertEqual(' 2 serial: Add a serial driver', next(itr)) - self.assertEqual(' 3 bootm: Make it boot', next(itr)) - self.assertEqual( - '1 new response available in patchwork (use -d to write them to ' - 'a new branch)', next(itr)) - - def test_series_status(self): - """Test getting the status of a series, including comments""" - cser, pwork = self.setup_second() - - # Use single threading for easy debugging, but the multithreaded - # version should produce the same output - with self.stage('status second2: single-threaded'): - with terminal.capture() as (out, _): - cser.status(pwork, 'second', 2, False) - self._check_status(out, False, False) - self.loop = asyncio.new_event_loop() - asyncio.set_event_loop(self.loop) - - with self.stage('status second2 (normal)'): - with terminal.capture() as (out2, _): - cser.status(pwork, 'second', 2, False) - self.assertEqual(out.getvalue(), out2.getvalue()) - self._check_status(out, False, False) - - with self.stage('with comments'): - with terminal.capture() as (out, _): - cser.status(pwork, 'second', 2, show_comments=True) - self._check_status(out, True, False) - - with self.stage('with comments and cover comments'): - with terminal.capture() as (out, _): - cser.status(pwork, 'second', 2, show_comments=True, - show_cover_comments=True) - self._check_status(out, True, True) - - def test_series_status_cmdline(self): - """Test getting the status of a series, including comments""" - cser, pwork = self.setup_second() - - with self.stage('status second2'): - with terminal.capture() as (out, _): - self.run_args('series', '-s', 'second', '-V', '2', 'status', - pwork=pwork) - self._check_status(out, False, False) - - with self.stage('status second2 (normal)'): - with terminal.capture() as (out, _): - cser.status(pwork, 'second', 2, show_comments=True) - self._check_status(out, True, False) - - with self.stage('with comments and cover comments'): - with terminal.capture() as (out, _): - cser.status(pwork, 'second', 2, show_comments=True, - show_cover_comments=True) - self._check_status(out, True, True) - - def test_series_no_subcmd(self): - """Test handling of things without a subcommand""" - parsers = cmdline.setup_parser() - parsers['series'].catch_error = True - with terminal.capture() as (out, _): - cmdline.parse_args(['series'], parsers=parsers) - self.assertIn('usage: patman series', out.getvalue()) - - parsers['patchwork'].catch_error = True - with terminal.capture() as (out, _): - cmdline.parse_args(['patchwork'], parsers=parsers) - self.assertIn('usage: patman patchwork', out.getvalue()) - - parsers['upstream'].catch_error = True - with terminal.capture() as (out, _): - cmdline.parse_args(['upstream'], parsers=parsers) - self.assertIn('usage: patman upstream', out.getvalue()) - - def check_series_rename(self): - """Check renaming a series""" - cser = self.get_cser() - with self.stage('setup'): - with terminal.capture() as (out, _): - cser.add('first', 'my name', allow_unmarked=True) - - # Remember the old series - old = cser.get_series_by_name('first') - - self.assertEqual('first', gitutil.get_branch(self.gitdir)) - with terminal.capture() as (out, _): - cser.increment('first') - self.assertEqual('first2', gitutil.get_branch(self.gitdir)) - - with terminal.capture() as (out, _): - cser.increment('first') - self.assertEqual('first3', gitutil.get_branch(self.gitdir)) - - # Do the dry run - with self.stage('rename - dry run'): - with terminal.capture() as (out, _): - yield cser - lines = out.getvalue().splitlines() - itr = iter(lines) - self.assertEqual("Renaming branch 'first' to 'newname'", next(itr)) - self.assertEqual( - "Renaming branch 'first2' to 'newname2'", next(itr)) - self.assertEqual( - "Renaming branch 'first3' to 'newname3'", next(itr)) - self.assertEqual("Renamed series 'first' to 'newname'", next(itr)) - self.assertEqual("Dry run completed", next(itr)) - self.assert_finished(itr) - - # Check nothing changed - self.assertEqual('first3', gitutil.get_branch(self.gitdir)) - sdict = cser.db.series_get_dict() - self.assertIn('first', sdict) - - # Now do it for real - with self.stage('rename - real'): - with terminal.capture() as (out2, _): - yield cser - lines2 = out2.getvalue().splitlines() - self.assertEqual(lines[:-1], lines2) - - self.assertEqual('newname3', gitutil.get_branch(self.gitdir)) - - # Check the series ID did not change - ser = cser.get_series_by_name('newname') - self.assertEqual(old.idnum, ser.idnum) - - yield None - - def test_series_rename(self): - """Test renaming of a series""" - cor = self.check_series_rename() - cser = next(cor) - - # Rename (dry run) - cser.rename('first', 'newname', dry_run=True) - cser = next(cor) - - # Rename (real) - cser.rename('first', 'newname') - self.assertFalse(next(cor)) - - def test_series_rename_cmdline(self): - """Test renaming of a series with the cmdline""" - cor = self.check_series_rename() - next(cor) - - # Rename (dry run) - self.run_args('series', '-n', '-s', 'first', 'rename', '-N', 'newname', - pwork=True) - next(cor) - - # Rename (real) - self.run_args('series', '-s', 'first', 'rename', '-N', 'newname', - pwork=True) - - self.assertFalse(next(cor)) - - def test_series_rename_bad(self): - """Test renaming when it is not allowed""" - cser = self.get_cser() - with terminal.capture(): - cser.add('first', 'my name', allow_unmarked=True) - cser.increment('first') - cser.increment('first') - - with self.assertRaises(ValueError) as exc: - cser.rename('first', 'first') - self.assertEqual("Cannot rename series 'first' to itself", - str(exc.exception)) - - with self.assertRaises(ValueError) as exc: - cser.rename('first2', 'newname') - self.assertEqual( - "Invalid series name 'first2': did you use the branch name?", - str(exc.exception)) - - with self.assertRaises(ValueError) as exc: - cser.rename('first', 'newname2') - self.assertEqual( - "Invalid series name 'newname2': did you use the branch name?", - str(exc.exception)) - - with self.assertRaises(ValueError) as exc: - cser.rename('first', 'second') - self.assertEqual("Cannot rename: branches exist: second", - str(exc.exception)) - - with terminal.capture(): - cser.add('second', 'another name', allow_unmarked=True) - cser.increment('second') - - with self.assertRaises(ValueError) as exc: - cser.rename('first', 'second') - self.assertEqual("Cannot rename: series 'second' already exists", - str(exc.exception)) - - # Rename second2 so that it gets in the way of the rename - gitutil.rename_branch('second2', 'newname2', self.gitdir) - with self.assertRaises(ValueError) as exc: - cser.rename('first', 'newname') - self.assertEqual("Cannot rename: branches exist: newname2", - str(exc.exception)) - - # Rename first3 and make sure it stops the rename - gitutil.rename_branch('first3', 'tempbranch', self.gitdir) - with self.assertRaises(ValueError) as exc: - cser.rename('first', 'newname') - self.assertEqual( - "Cannot rename: branches missing: first3: branches exist: " - 'newname2', str(exc.exception)) - - def test_version_change(self): - """Test changing a version of a series to a different version number""" - cser = self.get_cser() - - with self.stage('setup'): - with terminal.capture(): - cser.add('first', 'my description', allow_unmarked=True) - - with self.stage('non-existent version'): - # Check changing a non-existent version - with self.assertRaises(ValueError) as exc: - cser.version_change('first', 2, 3, dry_run=True) - self.assertEqual("Series 'first' does not have a version 2", - str(exc.exception)) - - with self.stage('new version missing'): - with self.assertRaises(ValueError) as exc: - cser.version_change('first', None, None, dry_run=True) - self.assertEqual("Please provide a new version number", - str(exc.exception)) - - # Change v1 to v2 (dry run) - with self.stage('v1 -> 2 dry run'): - with terminal.capture(): - self.assertTrue(gitutil.check_branch('first', self.gitdir)) - cser.version_change('first', 1, 3, dry_run=True) - self.assertTrue(gitutil.check_branch('first', self.gitdir)) - self.assertFalse(gitutil.check_branch('first3', self.gitdir)) - - # Check that nothing actually happened - series = patchstream.get_metadata('first', 0, 2, - git_dir=self.gitdir) - self.assertNotIn('version', series) - - svlist = cser.get_ser_ver_list() - self.assertEqual(1, len(svlist)) - item = svlist[0] - self.assertEqual(1, item.version) - - with self.stage('increment twice'): - # Increment so that we get first3 - with terminal.capture(): - cser.increment('first') - cser.increment('first') - - with self.stage('existing version'): - # Check changing to an existing version - with self.assertRaises(ValueError) as exc: - cser.version_change('first', 1, 3, dry_run=True) - self.assertEqual("Series 'first' already has a v3: 1 2 3", - str(exc.exception)) - - # Change v1 to v4 (for real) - with self.stage('v1 -> 4'): - with terminal.capture(): - self.assertTrue(gitutil.check_branch('first', self.gitdir)) - cser.version_change('first', 1, 4) - self.assertTrue(gitutil.check_branch('first', self.gitdir)) - self.assertTrue(gitutil.check_branch('first4', self.gitdir)) - - series = patchstream.get_metadata('first4', 0, 2, - git_dir=self.gitdir) - self.assertIn('version', series) - self.assertEqual('4', series.version) - - svdict = cser.get_ser_ver_dict() - self.assertEqual(3, len(svdict)) - item = svdict[item.idnum] - self.assertEqual(4, item.version) - - with self.stage('increment'): - # Now try to increment first again - with terminal.capture(): - cser.increment('first') - - ser = cser.get_series_by_name('first') - self.assertIn(5, cser._get_version_list(ser.idnum)) - - def test_version_change_cmdline(self): - """Check changing a version on the cmdline""" - self.get_cser() - with (mock.patch.object(cseries.Cseries, 'version_change', - return_value=None) as method): - self.run_args('series', '-s', 'first', 'version-change', - pwork=True) - method.assert_called_once_with('first', None, None, dry_run=False) - - with (mock.patch.object(cseries.Cseries, 'version_change', - return_value=None) as method): - self.run_args('series', '-s', 'first', 'version-change', - '--new-version', '3', pwork=True) - method.assert_called_once_with('first', None, 3, dry_run=False) diff --git a/tools/patman/test_settings.py b/tools/patman/test_settings.py deleted file mode 100644 index c117836de31..00000000000 --- a/tools/patman/test_settings.py +++ /dev/null @@ -1,67 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0+ -# -# Copyright (c) 2022 Maxim Cournoyer <[email protected]> -# - -import argparse -import contextlib -import os -import sys -import tempfile - -from patman import settings -from u_boot_pylib import tools - - -def empty_git_repository(): - with tempfile.TemporaryDirectory() as tmpdir: - os.chdir(tmpdir) - tools.run('git', 'init', raise_on_error=True) - yield tmpdir - - -def cleared_command_line_args(): - old_value = sys.argv[:] - sys.argv = [sys.argv[0]] - try: - yield - finally: - sys.argv = old_value - - -def test_git_local_config(): - # Clearing the command line arguments is required, otherwise - # arguments passed to the test running such as in 'pytest -k - # filter' would be processed by _UpdateDefaults and fail. - with cleared_command_line_args(): - with empty_git_repository(): - with tempfile.NamedTemporaryFile() as global_config: - global_config.write(b'[settings]\n' - b'project=u-boot\n') - global_config.flush() - parser = argparse.ArgumentParser() - parser.add_argument('-p', '--project', default='unknown') - subparsers = parser.add_subparsers(dest='cmd') - send = subparsers.add_parser('send') - send.add_argument('--no-check', action='store_false', - dest='check_patch', default=True) - - # Test "global" config is used. - settings.Setup(parser, 'unknown', None, global_config.name) - args, _ = parser.parse_known_args([]) - assert args.project == 'u-boot' - send_args, _ = send.parse_known_args([]) - assert send_args.check_patch - - # Test local config can shadow it. - with open('.patman', 'w', buffering=1) as f: - f.write('[settings]\n' - 'project: guix-patches\n' - 'check_patch: False\n') - settings.Setup(parser, 'unknown', global_config.name) - args, _ = parser.parse_known_args([]) - assert args.project == 'guix-patches' - send_args, _ = send.parse_known_args([]) - assert not send_args.check_patch |
