diff options
Diffstat (limited to 'tools/patman/test_common.py')
-rw-r--r-- | tools/patman/test_common.py | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/tools/patman/test_common.py b/tools/patman/test_common.py new file mode 100644 index 00000000000..7da995dda22 --- /dev/null +++ b/tools/patman/test_common.py @@ -0,0 +1,254 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2025 Simon Glass <sjg@chromium.org> +# +"""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 <weasel@blackadder.org>'. + 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', 'test@email.com') + 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', 'dumdum@dummy.com']), + cwd=self.gitdir) + + # pylint doesn't seem to find this + # pylint: disable=E1101 + author = pygit2.Signature('Test user', 'test@email.com') + 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 <bcrump@whataroa.nz> +''') + 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 |