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 | 
