diff options
author | bst-marge-bot <marge-bot@buildstream.build> | 2019-04-15 09:00:51 +0000 |
---|---|---|
committer | bst-marge-bot <marge-bot@buildstream.build> | 2019-04-15 09:00:51 +0000 |
commit | b9eec0cadcc05d1d791beb4a1411400c19bedb0b (patch) | |
tree | b5f9ccc6ec40fc765e741957b614646511ff54ef | |
parent | 92c9a04747a9773c0036578db9cb3fa9acb12247 (diff) | |
parent | c90cf9e8680350a75f4a76b464fdf7fe4dab4016 (diff) | |
download | buildstream-b9eec0cadcc05d1d791beb4a1411400c19bedb0b.tar.gz |
Merge branch 'phil/expose-templated-tests' into 'master'
Expose templated source tests
See merge request BuildStream/buildstream!1261
74 files changed, 415 insertions, 183 deletions
diff --git a/MANIFEST.in b/MANIFEST.in index a8899a91e..4365f0df1 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -6,6 +6,9 @@ include MAINTAINERS include NEWS include README.rst +# Data files required by BuildStream's generic source tests +recursive-include buildstream/plugintestutils/_sourcetests/project * + # Documentation package includes include doc/Makefile include doc/badges.py diff --git a/buildstream/plugintestutils/__init__.py b/buildstream/plugintestutils/__init__.py index 9ec18df19..19cb1bf9a 100644 --- a/buildstream/plugintestutils/__init__.py +++ b/buildstream/plugintestutils/__init__.py @@ -15,7 +15,14 @@ # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see <http://www.gnu.org/licenses/>. +""" +This package contains various utilities which make it easier to test plugins. +""" +import os +from collections import OrderedDict +from . import _sourcetests +from .repo import Repo from .runcli import cli, cli_integration, cli_remote_execution # To make use of these test utilities it is necessary to have pytest @@ -28,3 +35,64 @@ except ImportError: msg = "Could not import pytest:\n" \ "To use the {} module, you must have pytest installed.".format(module_name) raise ImportError(msg) + + +ALL_REPO_KINDS = OrderedDict() + + +def create_repo(kind, directory, subdir='repo'): + """Convenience method for creating a Repo + + Args: + kind (str): The kind of repo to create (a source plugin basename). This + must have previously been registered using + `register_repo_kind` + directory (str): The path where the repo will keep a cache + + Returns: + (Repo): A new Repo object + """ + try: + constructor = ALL_REPO_KINDS[kind] + except KeyError as e: + raise AssertionError("Unsupported repo kind {}".format(kind)) from e + + return constructor(directory, subdir=subdir) + + +def register_repo_kind(kind, cls): + """Register a new repo kind. + + Registering a repo kind will allow the use of the `create_repo` + method for that kind and include that repo kind in ALL_REPO_KINDS + + In addition, repo_kinds registred prior to + `sourcetests_collection_hook` being called will be automatically + used to test the basic behaviour of their associated source + plugins using the tests in `plugintestutils._sourcetests`. + + Args: + kind (str): The kind of repo to create (a source plugin basename) + cls (cls) : A class derived from Repo. + + """ + ALL_REPO_KINDS[kind] = cls + + +def sourcetests_collection_hook(session): + """ Used to hook the templated source plugin tests into a pyest test suite. + + This should be called via the `pytest_sessionstart + hook <https://docs.pytest.org/en/latest/reference.html#collection-hooks>`_. + The tests in the _sourcetests package will be collected as part of + whichever test package this hook is called from. + + Args: + session (pytest.Session): The current pytest session + """ + SOURCE_TESTS_PATH = os.path.dirname(_sourcetests.__file__) + # Add the location of the source tests to the session's + # python_files config. Without this, pytest may filter out these + # tests during collection. + session.config.addinivalue_line("python_files", os.path.join(SOURCE_TESTS_PATH, "*.py")) + session.config.args.append(SOURCE_TESTS_PATH) diff --git a/tests/sources/generic/__init__.py b/buildstream/plugintestutils/_sourcetests/__init__.py index e69de29bb..e69de29bb 100644 --- a/tests/sources/generic/__init__.py +++ b/buildstream/plugintestutils/_sourcetests/__init__.py diff --git a/tests/sources/generic/build_checkout.py b/buildstream/plugintestutils/_sourcetests/build_checkout.py index e113b40cb..074be8429 100644 --- a/tests/sources/generic/build_checkout.py +++ b/buildstream/plugintestutils/_sourcetests/build_checkout.py @@ -22,8 +22,7 @@ import os import pytest -from tests.testutils import create_repo, ALL_REPO_KINDS - +from buildstream.plugintestutils import create_repo, ALL_REPO_KINDS from buildstream.plugintestutils import cli # pylint: disable=unused-import from buildstream import _yaml diff --git a/tests/sources/generic/fetch.py b/buildstream/plugintestutils/_sourcetests/fetch.py index f5931f8f1..aaf92a14d 100644 --- a/tests/sources/generic/fetch.py +++ b/buildstream/plugintestutils/_sourcetests/fetch.py @@ -22,12 +22,10 @@ import os import pytest -from tests.testutils import create_repo, ALL_REPO_KINDS, generate_junction -from tests.frontend import configure_project - -from buildstream.plugintestutils import cli # pylint: disable=unused-import from buildstream import _yaml - +from .._utils import generate_junction, configure_project +from .. import create_repo, ALL_REPO_KINDS +from .. import cli # pylint: disable=unused-import # Project directory TOP_DIR = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/sources/generic/mirror.py b/buildstream/plugintestutils/_sourcetests/mirror.py index e9fe254c5..d682bb2ef 100644 --- a/tests/sources/generic/mirror.py +++ b/buildstream/plugintestutils/_sourcetests/mirror.py @@ -22,11 +22,11 @@ import os import pytest -from tests.testutils import create_repo, ALL_REPO_KINDS, generate_junction - -from buildstream.plugintestutils import cli # pylint: disable=unused-import from buildstream import _yaml from buildstream._exceptions import ErrorDomain +from .._utils import generate_junction +from .. import create_repo, ALL_REPO_KINDS +from .. import cli # pylint: disable=unused-import # Project directory TOP_DIR = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/sources/generic/project/elements/base.bst b/buildstream/plugintestutils/_sourcetests/project/elements/base.bst index 428afa736..428afa736 100644 --- a/tests/sources/generic/project/elements/base.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/base.bst diff --git a/tests/sources/generic/project/elements/base/base-alpine.bst b/buildstream/plugintestutils/_sourcetests/project/elements/base/base-alpine.bst index c5833095d..c5833095d 100644 --- a/tests/sources/generic/project/elements/base/base-alpine.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/base/base-alpine.bst diff --git a/tests/sources/generic/project/elements/import-bin.bst b/buildstream/plugintestutils/_sourcetests/project/elements/import-bin.bst index a847c0c23..a847c0c23 100644 --- a/tests/sources/generic/project/elements/import-bin.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/import-bin.bst diff --git a/tests/sources/generic/project/elements/import-dev.bst b/buildstream/plugintestutils/_sourcetests/project/elements/import-dev.bst index 152a54667..152a54667 100644 --- a/tests/sources/generic/project/elements/import-dev.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/import-dev.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/dependency/horsey.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/dependency/horsey.bst index bd1ffae9c..bd1ffae9c 100644 --- a/tests/sources/generic/project/elements/multiple_targets/dependency/horsey.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/dependency/horsey.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/dependency/pony.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/dependency/pony.bst index 3c29b4ea1..3c29b4ea1 100644 --- a/tests/sources/generic/project/elements/multiple_targets/dependency/pony.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/dependency/pony.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/dependency/zebry.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/dependency/zebry.bst index 98447ab52..98447ab52 100644 --- a/tests/sources/generic/project/elements/multiple_targets/dependency/zebry.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/dependency/zebry.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/order/0.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/0.bst index a99be06a0..a99be06a0 100644 --- a/tests/sources/generic/project/elements/multiple_targets/order/0.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/0.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/order/1.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/1.bst index 82b507a62..82b507a62 100644 --- a/tests/sources/generic/project/elements/multiple_targets/order/1.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/1.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/order/2.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/2.bst index ee1afae20..ee1afae20 100644 --- a/tests/sources/generic/project/elements/multiple_targets/order/2.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/2.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/order/3.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/3.bst index 4c3a23dab..4c3a23dab 100644 --- a/tests/sources/generic/project/elements/multiple_targets/order/3.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/3.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/order/4.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/4.bst index b663a0b52..b663a0b52 100644 --- a/tests/sources/generic/project/elements/multiple_targets/order/4.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/4.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/order/5.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/5.bst index b9efcf71b..b9efcf71b 100644 --- a/tests/sources/generic/project/elements/multiple_targets/order/5.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/5.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/order/6.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/6.bst index 6c19d04e3..6c19d04e3 100644 --- a/tests/sources/generic/project/elements/multiple_targets/order/6.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/6.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/order/7.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/7.bst index 6805b3e6d..6805b3e6d 100644 --- a/tests/sources/generic/project/elements/multiple_targets/order/7.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/7.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/order/8.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/8.bst index b8d8964a0..b8d8964a0 100644 --- a/tests/sources/generic/project/elements/multiple_targets/order/8.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/8.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/order/9.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/9.bst index cc13bf3f0..cc13bf3f0 100644 --- a/tests/sources/generic/project/elements/multiple_targets/order/9.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/9.bst diff --git a/tests/sources/generic/project/elements/multiple_targets/order/run.bst b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/run.bst index 9b3d2446c..9b3d2446c 100644 --- a/tests/sources/generic/project/elements/multiple_targets/order/run.bst +++ b/buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/run.bst diff --git a/tests/sources/generic/project/files/bar b/buildstream/plugintestutils/_sourcetests/project/files/bar index e69de29bb..e69de29bb 100644 --- a/tests/sources/generic/project/files/bar +++ b/buildstream/plugintestutils/_sourcetests/project/files/bar diff --git a/tests/sources/generic/project/files/bin-files/usr/bin/hello b/buildstream/plugintestutils/_sourcetests/project/files/bin-files/usr/bin/hello index f534a4083..f534a4083 100755 --- a/tests/sources/generic/project/files/bin-files/usr/bin/hello +++ b/buildstream/plugintestutils/_sourcetests/project/files/bin-files/usr/bin/hello diff --git a/tests/sources/generic/project/files/dev-files/usr/include/pony.h b/buildstream/plugintestutils/_sourcetests/project/files/dev-files/usr/include/pony.h index 40bd0c2e7..40bd0c2e7 100644 --- a/tests/sources/generic/project/files/dev-files/usr/include/pony.h +++ b/buildstream/plugintestutils/_sourcetests/project/files/dev-files/usr/include/pony.h diff --git a/tests/sources/generic/project/files/etc-files/etc/buildstream/config b/buildstream/plugintestutils/_sourcetests/project/files/etc-files/etc/buildstream/config index 04204c7c9..04204c7c9 100644 --- a/tests/sources/generic/project/files/etc-files/etc/buildstream/config +++ b/buildstream/plugintestutils/_sourcetests/project/files/etc-files/etc/buildstream/config diff --git a/tests/sources/generic/project/files/foo b/buildstream/plugintestutils/_sourcetests/project/files/foo index e69de29bb..e69de29bb 100644 --- a/tests/sources/generic/project/files/foo +++ b/buildstream/plugintestutils/_sourcetests/project/files/foo diff --git a/tests/sources/generic/project/files/source-bundle/llamas.txt b/buildstream/plugintestutils/_sourcetests/project/files/source-bundle/llamas.txt index f98b24871..f98b24871 100644 --- a/tests/sources/generic/project/files/source-bundle/llamas.txt +++ b/buildstream/plugintestutils/_sourcetests/project/files/source-bundle/llamas.txt diff --git a/tests/sources/generic/project/files/sub-project/elements/import-etc.bst b/buildstream/plugintestutils/_sourcetests/project/files/sub-project/elements/import-etc.bst index f0171990e..f0171990e 100644 --- a/tests/sources/generic/project/files/sub-project/elements/import-etc.bst +++ b/buildstream/plugintestutils/_sourcetests/project/files/sub-project/elements/import-etc.bst diff --git a/tests/sources/generic/project/files/sub-project/files/etc-files/etc/animal.conf b/buildstream/plugintestutils/_sourcetests/project/files/sub-project/files/etc-files/etc/animal.conf index db8c36cba..db8c36cba 100644 --- a/tests/sources/generic/project/files/sub-project/files/etc-files/etc/animal.conf +++ b/buildstream/plugintestutils/_sourcetests/project/files/sub-project/files/etc-files/etc/animal.conf diff --git a/tests/sources/generic/project/files/sub-project/project.conf b/buildstream/plugintestutils/_sourcetests/project/files/sub-project/project.conf index bbb8414a3..bbb8414a3 100644 --- a/tests/sources/generic/project/files/sub-project/project.conf +++ b/buildstream/plugintestutils/_sourcetests/project/files/sub-project/project.conf diff --git a/tests/sources/generic/project/project.conf b/buildstream/plugintestutils/_sourcetests/project/project.conf index 05b68bfeb..05b68bfeb 100644 --- a/tests/sources/generic/project/project.conf +++ b/buildstream/plugintestutils/_sourcetests/project/project.conf diff --git a/tests/sources/generic/source_determinism.py b/buildstream/plugintestutils/_sourcetests/source_determinism.py index 3488e3beb..8597a7072 100644 --- a/tests/sources/generic/source_determinism.py +++ b/buildstream/plugintestutils/_sourcetests/source_determinism.py @@ -22,11 +22,10 @@ import os import pytest -from tests.testutils import create_repo, ALL_REPO_KINDS -from tests.testutils.site import HAVE_SANDBOX - -from buildstream.plugintestutils import cli # pylint: disable=unused-import from buildstream import _yaml +from .._utils.site import HAVE_SANDBOX +from .. import create_repo, ALL_REPO_KINDS +from .. import cli # pylint: disable=unused-import # Project directory TOP_DIR = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/sources/generic/track.py b/buildstream/plugintestutils/_sourcetests/track.py index 4c65602e9..668ea29e5 100644 --- a/tests/sources/generic/track.py +++ b/buildstream/plugintestutils/_sourcetests/track.py @@ -22,13 +22,11 @@ import os import pytest -from tests.testutils import create_repo, ALL_REPO_KINDS, generate_junction -from tests.frontend import configure_project - -from buildstream.plugintestutils import cli # pylint: disable=unused-import from buildstream import _yaml from buildstream._exceptions import ErrorDomain - +from .._utils import generate_junction, configure_project +from .. import create_repo, ALL_REPO_KINDS +from .. import cli # pylint: disable=unused-import # Project directory TOP_DIR = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/sources/generic/track_cross_junction.py b/buildstream/plugintestutils/_sourcetests/track_cross_junction.py index 56969619d..ece3e0b8f 100644 --- a/tests/sources/generic/track_cross_junction.py +++ b/buildstream/plugintestutils/_sourcetests/track_cross_junction.py @@ -22,10 +22,10 @@ import os import pytest -from tests.testutils import create_repo, ALL_REPO_KINDS, generate_junction - -from buildstream.plugintestutils import cli # pylint: disable=unused-import from buildstream import _yaml +from .._utils import generate_junction +from .. import create_repo, ALL_REPO_KINDS +from .. import cli # pylint: disable=unused-import # Project directory TOP_DIR = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/sources/generic/workspace.py b/buildstream/plugintestutils/_sourcetests/workspace.py index ad115c1ba..5218f8f1e 100644 --- a/tests/sources/generic/workspace.py +++ b/buildstream/plugintestutils/_sourcetests/workspace.py @@ -23,10 +23,9 @@ import os import shutil import pytest -from tests.testutils import create_repo, ALL_REPO_KINDS - -from buildstream.plugintestutils import cli # pylint: disable=unused-import from buildstream import _yaml +from .. import create_repo, ALL_REPO_KINDS +from .. import cli # pylint: disable=unused-import # Project directory TOP_DIR = os.path.dirname(os.path.realpath(__file__)) diff --git a/buildstream/plugintestutils/_utils/__init__.py b/buildstream/plugintestutils/_utils/__init__.py new file mode 100644 index 000000000..b419d72b7 --- /dev/null +++ b/buildstream/plugintestutils/_utils/__init__.py @@ -0,0 +1,10 @@ +import os + +from buildstream import _yaml +from .junction import generate_junction + + +def configure_project(path, config): + config['name'] = 'test' + config['element-path'] = 'elements' + _yaml.dump(config, os.path.join(path, 'project.conf')) diff --git a/buildstream/plugintestutils/_utils/junction.py b/buildstream/plugintestutils/_utils/junction.py new file mode 100644 index 000000000..ca059eb8b --- /dev/null +++ b/buildstream/plugintestutils/_utils/junction.py @@ -0,0 +1,83 @@ +import subprocess +import pytest + +from buildstream import _yaml +from .. import Repo +from .site import HAVE_GIT, GIT, GIT_ENV + + +# generate_junction() +# +# Generates a junction element with a git repository +# +# Args: +# tmpdir: The tmpdir fixture, for storing the generated git repo +# subproject_path: The path for the subproject, to add to the git repo +# junction_path: The location to store the generated junction element +# store_ref: Whether to store the ref in the junction.bst file +# +# Returns: +# (str): The ref +# +def generate_junction(tmpdir, subproject_path, junction_path, *, store_ref=True): + # Create a repo to hold the subproject and generate + # a junction element for it + # + repo = _SimpleGit(str(tmpdir)) + source_ref = ref = repo.create(subproject_path) + if not store_ref: + source_ref = None + + element = { + 'kind': 'junction', + 'sources': [ + repo.source_config(ref=source_ref) + ] + } + _yaml.dump(element, junction_path) + + return ref + + +# A barebones Git Repo class to use for generating junctions +class _SimpleGit(Repo): + def __init__(self, directory, subdir='repo'): + if not HAVE_GIT: + pytest.skip('git is not available') + super().__init__(directory, subdir) + + def create(self, directory): + self.copy_directory(directory, self.repo) + self._run_git('init', '.') + self._run_git('add', '.') + self._run_git('commit', '-m', 'Initial commit') + return self.latest_commit() + + def latest_commit(self): + return self._run_git( + 'rev-parse', 'HEAD', + stdout=subprocess.PIPE, + universal_newlines=True, + ).stdout.strip() + + def source_config(self, ref=None, checkout_submodules=None): + config = { + 'kind': 'git', + 'url': 'file://' + self.repo, + 'track': 'master' + } + if ref is not None: + config['ref'] = ref + if checkout_submodules is not None: + config['checkout-submodules'] = checkout_submodules + + return config + + def _run_git(self, *args, **kwargs): + argv = [GIT] + argv.extend(args) + if 'env' not in kwargs: + kwargs['env'] = dict(GIT_ENV, PWD=self.repo) + kwargs.setdefault('cwd', self.repo) + kwargs.setdefault('check', True) + return subprocess.run(argv, **kwargs) diff --git a/buildstream/plugintestutils/_utils/site.py b/buildstream/plugintestutils/_utils/site.py new file mode 100644 index 000000000..54c5b467b --- /dev/null +++ b/buildstream/plugintestutils/_utils/site.py @@ -0,0 +1,46 @@ +# Some things resolved about the execution site, +# so we dont have to repeat this everywhere +# +import os +import sys +import platform + +from buildstream import _site, utils, ProgramNotFoundError + + +try: + GIT = utils.get_host_tool('git') + HAVE_GIT = True + GIT_ENV = { + 'GIT_AUTHOR_DATE': '1320966000 +0200', + 'GIT_AUTHOR_NAME': 'tomjon', + 'GIT_AUTHOR_EMAIL': 'tom@jon.com', + 'GIT_COMMITTER_DATE': '1320966000 +0200', + 'GIT_COMMITTER_NAME': 'tomjon', + 'GIT_COMMITTER_EMAIL': 'tom@jon.com' + } +except ProgramNotFoundError: + GIT = None + HAVE_GIT = False + GIT_ENV = dict() + +try: + utils.get_host_tool('bwrap') + HAVE_BWRAP = True + HAVE_BWRAP_JSON_STATUS = _site.get_bwrap_version() >= (0, 3, 2) +except ProgramNotFoundError: + HAVE_BWRAP = False + HAVE_BWRAP_JSON_STATUS = False + +IS_LINUX = os.getenv('BST_FORCE_BACKEND', sys.platform).startswith('linux') +IS_WSL = (IS_LINUX and 'Microsoft' in platform.uname().release) +IS_WINDOWS = (os.name == 'nt') + +if not IS_LINUX: + HAVE_SANDBOX = True # fallback to a chroot sandbox on unix +elif IS_WSL: + HAVE_SANDBOX = False # Sandboxes are inoperable under WSL due to lack of FUSE +elif IS_LINUX and HAVE_BWRAP: + HAVE_SANDBOX = True +else: + HAVE_SANDBOX = False diff --git a/buildstream/plugintestutils/repo.py b/buildstream/plugintestutils/repo.py new file mode 100644 index 000000000..e3293ea75 --- /dev/null +++ b/buildstream/plugintestutils/repo.py @@ -0,0 +1,109 @@ +# +# Copyright (C) 2016-2018 Codethink Limited +# Copyright (C) 2019 Bloomberg Finance LP +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see <http://www.gnu.org/licenses/>. + +""" +Repo - Utility class for testing source plugins +=============================================== + + +""" +import os +import shutil + + +class Repo(): + """Repo() + + Abstract class providing scaffolding for generating data to be + used with various sources. Subclasses of Repo may be registered to + run through the suite of generic source plugin tests provided in + buildstream.plugintestutils. + + Args: + directory (str): The base temp directory for the test + subdir (str): The subdir for the repo, in case there is more than one + + """ + def __init__(self, directory, subdir='repo'): + + # The working directory for the repo object + # + self.directory = os.path.abspath(directory) + + # The directory the actual repo will be stored in + self.repo = os.path.join(self.directory, subdir) + + os.makedirs(self.repo, exist_ok=True) + + def create(self, directory): + """Create a repository in self.directory and add the initial content + + Args: + directory: A directory with content to commit + + Returns: + (smth): A new ref corresponding to this commit, which can + be passed as the ref in the Repo.source_config() API. + """ + raise NotImplementedError("create method has not been implemeted") + + def source_config(self, ref=None): + """ + Args: + ref (smth): An optional abstract ref object, usually a string. + + Returns: + (dict): A configuration which can be serialized as a + source when generating an element file on the fly + + """ + raise NotImplementedError("source_config method has not been implemeted") + + def copy_directory(self, src, dest): + """ Copies the content of src to the directory dest + + Like shutil.copytree(), except dest is expected + to exist. + + Args: + src (str): The source directory + dest (str): The destination directory + """ + for filename in os.listdir(src): + src_path = os.path.join(src, filename) + dest_path = os.path.join(dest, filename) + if os.path.isdir(src_path): + shutil.copytree(src_path, dest_path) + else: + shutil.copy2(src_path, dest_path) + + def copy(self, dest): + """Creates a copy of this repository in the specified destination. + + Args: + dest (str): The destination directory + + Returns: + (Repo): A Repo object for the new repository. + """ + subdir = self.repo[len(self.directory):].lstrip(os.sep) + new_dir = os.path.join(dest, subdir) + os.makedirs(new_dir, exist_ok=True) + self.copy_directory(self.repo, new_dir) + repo_type = type(self) + new_repo = repo_type(dest, subdir) + return new_repo diff --git a/doc/source/core_framework.rst b/doc/source/core_framework.rst index a66f3640f..127b5b2c6 100644 --- a/doc/source/core_framework.rst +++ b/doc/source/core_framework.rst @@ -20,3 +20,4 @@ useful for working on BuildStream itself. buildstream.scriptelement buildstream.sandbox.sandbox buildstream.utils + buildstream.plugintestutils @@ -323,6 +323,7 @@ setup(name='BuildStream', packages=find_packages(exclude=('tests', 'tests.*')), package_data={'buildstream': ['plugins/*/*.py', 'plugins/*/*.yaml', 'data/*.yaml', 'data/*.sh.in']}, + include_package_data=True, data_files=[ # This is a weak attempt to integrate with the user nicely, # installing things outside of the python package itself with pip is diff --git a/tests/conftest.py b/tests/conftest.py index 30577870f..fefd2f755 100755 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # # Copyright (C) 2018 Codethink Limited +# Copyright (C) 2019 Bloomberg Finance LLP # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -23,6 +24,14 @@ import shutil import tempfile import pytest from buildstream._platform.platform import Platform +from buildstream.plugintestutils import register_repo_kind, sourcetests_collection_hook + +from tests.testutils.repo.git import Git +from tests.testutils.repo.bzr import Bzr +from tests.testutils.repo.ostree import OSTree +from tests.testutils.repo.tar import Tar +from tests.testutils.repo.zip import Zip + # # This file is loaded by pytest, we use it to add a custom @@ -155,3 +164,19 @@ def clean_platform_cache(): @pytest.fixture(autouse=True) def ensure_platform_cache_is_clean(): clean_platform_cache() + + +################################################# +# Setup for templated source tests # +################################################# +register_repo_kind('git', Git) +register_repo_kind('bzr', Bzr) +register_repo_kind('ostree', OSTree) +register_repo_kind('tar', Tar) +register_repo_kind('zip', Zip) + + +# This hook enables pytest to collect the templated source tests from +# buildstream.plugintestutils +def pytest_sessionstart(session): + sourcetests_collection_hook(session) diff --git a/tests/elements/filter.py b/tests/elements/filter.py index 1579bf06c..2c5ca88b7 100644 --- a/tests/elements/filter.py +++ b/tests/elements/filter.py @@ -6,7 +6,7 @@ import shutil import pytest -from tests.testutils import create_repo +from buildstream.plugintestutils import create_repo from buildstream.plugintestutils import cli # pylint: disable=unused-import from buildstream._exceptions import ErrorDomain from buildstream import _yaml diff --git a/tests/format/include.py b/tests/format/include.py index 793bdb0e4..73f8092c5 100644 --- a/tests/format/include.py +++ b/tests/format/include.py @@ -7,8 +7,8 @@ import pytest from buildstream import _yaml from buildstream._exceptions import ErrorDomain, LoadErrorReason from buildstream.plugintestutils import cli # pylint: disable=unused-import - -from tests.testutils import generate_junction, create_repo +from buildstream.plugintestutils import create_repo +from tests.testutils import generate_junction # Project directory diff --git a/tests/format/junctions.py b/tests/format/junctions.py index 3a215761a..94562cb4e 100644 --- a/tests/format/junctions.py +++ b/tests/format/junctions.py @@ -9,7 +9,7 @@ import pytest from buildstream import _yaml from buildstream._exceptions import ErrorDomain, LoadErrorReason from buildstream.plugintestutils import cli # pylint: disable=unused-import -from tests.testutils import create_repo +from buildstream.plugintestutils import create_repo from tests.testutils.site import HAVE_GIT diff --git a/tests/frontend/buildtrack.py b/tests/frontend/buildtrack.py index 5a3781dc6..d4dc93aac 100644 --- a/tests/frontend/buildtrack.py +++ b/tests/frontend/buildtrack.py @@ -8,9 +8,8 @@ import itertools import pytest -from tests.testutils import create_repo - from buildstream import _yaml +from buildstream.plugintestutils import create_repo from buildstream.plugintestutils import cli # pylint: disable=unused-import from buildstream._exceptions import ErrorDomain diff --git a/tests/frontend/cross_junction_workspace.py b/tests/frontend/cross_junction_workspace.py index 88bda857d..a93d5c132 100644 --- a/tests/frontend/cross_junction_workspace.py +++ b/tests/frontend/cross_junction_workspace.py @@ -3,10 +3,9 @@ import os from buildstream.plugintestutils import cli # pylint: disable=unused-import +from buildstream.plugintestutils import create_repo from buildstream import _yaml -from tests.testutils import create_repo - def prepare_junction_project(cli, tmpdir): main_project = tmpdir.join("main") diff --git a/tests/frontend/fetch.py b/tests/frontend/fetch.py index 8282e2131..cea7ff129 100644 --- a/tests/frontend/fetch.py +++ b/tests/frontend/fetch.py @@ -4,8 +4,8 @@ import os import pytest -from tests.testutils import create_repo, generate_junction, yaml_file_get_provenance - +from tests.testutils import generate_junction, yaml_file_get_provenance +from buildstream.plugintestutils import create_repo from buildstream.plugintestutils import cli # pylint: disable=unused-import from buildstream import _yaml from buildstream._exceptions import ErrorDomain, LoadErrorReason diff --git a/tests/frontend/logging.py b/tests/frontend/logging.py index 4036a4693..49e3a70c6 100644 --- a/tests/frontend/logging.py +++ b/tests/frontend/logging.py @@ -6,7 +6,7 @@ import re import pytest -from tests.testutils import create_repo +from buildstream.plugintestutils import create_repo from buildstream import _yaml from buildstream._exceptions import ErrorDomain diff --git a/tests/frontend/mirror.py b/tests/frontend/mirror.py index b33d889c6..47f94289f 100644 --- a/tests/frontend/mirror.py +++ b/tests/frontend/mirror.py @@ -4,9 +4,8 @@ import os import pytest -from tests.testutils import create_repo - from buildstream import _yaml +from buildstream.plugintestutils import create_repo from buildstream.plugintestutils import cli # pylint: disable=unused-import diff --git a/tests/frontend/order.py b/tests/frontend/order.py index cd75aa6b7..5eb5b299d 100644 --- a/tests/frontend/order.py +++ b/tests/frontend/order.py @@ -4,7 +4,7 @@ import os import pytest -from tests.testutils import create_repo +from buildstream.plugintestutils import create_repo from buildstream.plugintestutils import cli # pylint: disable=unused-import from buildstream import _yaml diff --git a/tests/frontend/track.py b/tests/frontend/track.py index 46f5bcf67..17d0cd827 100644 --- a/tests/frontend/track.py +++ b/tests/frontend/track.py @@ -4,12 +4,12 @@ import stat import os import pytest -from tests.testutils import create_repo, generate_junction, yaml_file_get_provenance +from buildstream.plugintestutils import create_repo from buildstream.plugintestutils import cli # pylint: disable=unused-import from buildstream._exceptions import ErrorDomain, LoadErrorReason from buildstream import _yaml - +from tests.testutils import generate_junction, yaml_file_get_provenance from . import configure_project # Project directory diff --git a/tests/frontend/workspace.py b/tests/frontend/workspace.py index 78f3600d1..522bbffab 100644 --- a/tests/frontend/workspace.py +++ b/tests/frontend/workspace.py @@ -34,9 +34,9 @@ import subprocess import pytest -from tests.testutils import create_repo, ALL_REPO_KINDS, wait_for_cache_granularity -from tests.testutils import create_artifact_share, create_element_size +from tests.testutils import create_artifact_share, create_element_size, wait_for_cache_granularity +from buildstream.plugintestutils import create_repo, ALL_REPO_KINDS from buildstream.plugintestutils import cli # pylint: disable=unused-import from buildstream import _yaml from buildstream._exceptions import ErrorDomain, LoadErrorReason diff --git a/tests/integration/source-determinism.py b/tests/integration/source-determinism.py index 7cfca98e0..2f63a4af9 100644 --- a/tests/integration/source-determinism.py +++ b/tests/integration/source-determinism.py @@ -3,7 +3,7 @@ import pytest from buildstream import _yaml from buildstream.plugintestutils import cli_integration as cli -from tests.testutils import create_repo +from buildstream.plugintestutils import create_repo from tests.testutils.site import HAVE_SANDBOX diff --git a/tests/sourcecache/fetch.py b/tests/sourcecache/fetch.py index 86d2138c0..7f82388ab 100644 --- a/tests/sourcecache/fetch.py +++ b/tests/sourcecache/fetch.py @@ -28,8 +28,8 @@ from buildstream._context import Context from buildstream._project import Project from buildstream import _yaml from buildstream.plugintestutils import cli # pylint: disable=unused-import - -from tests.testutils import create_artifact_share, create_repo +from buildstream.plugintestutils import create_repo +from tests.testutils import create_artifact_share DATA_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "project") diff --git a/tests/sourcecache/push.py b/tests/sourcecache/push.py index f692136bb..825d2614e 100644 --- a/tests/sourcecache/push.py +++ b/tests/sourcecache/push.py @@ -28,8 +28,9 @@ from buildstream._exceptions import ErrorDomain from buildstream._project import Project from buildstream import _yaml from buildstream.plugintestutils import cli # pylint: disable=unused-import +from buildstream.plugintestutils import create_repo -from tests.testutils import create_artifact_share, create_repo +from tests.testutils import create_artifact_share DATA_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "project") diff --git a/tests/sources/bzr.py b/tests/sources/bzr.py index 0a3c345bd..bf022236b 100644 --- a/tests/sources/bzr.py +++ b/tests/sources/bzr.py @@ -7,7 +7,7 @@ import pytest from buildstream import _yaml from buildstream.plugintestutils import cli # pylint: disable=unused-import -from tests.testutils import create_repo +from buildstream.plugintestutils import create_repo from tests.testutils.site import HAVE_BZR DATA_DIR = os.path.join( diff --git a/tests/sources/git.py b/tests/sources/git.py index dd53df2b5..0f97b77a3 100644 --- a/tests/sources/git.py +++ b/tests/sources/git.py @@ -33,8 +33,8 @@ from buildstream._exceptions import ErrorDomain from buildstream import _yaml from buildstream.plugin import CoreWarnings from buildstream.plugintestutils import cli # pylint: disable=unused-import +from buildstream.plugintestutils import create_repo -from tests.testutils import create_repo from tests.testutils.site import HAVE_GIT, HAVE_OLD_GIT DATA_DIR = os.path.join( diff --git a/tests/sources/no_fetch_cached.py b/tests/sources/no_fetch_cached.py index 767c193d2..4a3f71932 100644 --- a/tests/sources/no_fetch_cached.py +++ b/tests/sources/no_fetch_cached.py @@ -7,7 +7,7 @@ import pytest from buildstream import _yaml from buildstream.plugintestutils import cli # pylint: disable=unused-import -from tests.testutils import create_repo +from buildstream.plugintestutils import create_repo from tests.testutils.site import HAVE_GIT DATA_DIR = os.path.join( diff --git a/tests/sources/ostree.py b/tests/sources/ostree.py index 2d4dd953a..e75a64663 100644 --- a/tests/sources/ostree.py +++ b/tests/sources/ostree.py @@ -26,8 +26,7 @@ import pytest from buildstream._exceptions import ErrorDomain from buildstream import _yaml from buildstream.plugintestutils import cli # pylint: disable=unused-import - -from tests.testutils import create_repo +from buildstream.plugintestutils import create_repo DATA_DIR = os.path.join( os.path.dirname(os.path.realpath(__file__)), diff --git a/tests/testutils/__init__.py b/tests/testutils/__init__.py index 929ffc5f2..2e1f72138 100644 --- a/tests/testutils/__init__.py +++ b/tests/testutils/__init__.py @@ -23,7 +23,6 @@ # William Salmon <will.salmon@codethink.co.uk> # -from .repo import create_repo, ALL_REPO_KINDS from .artifactshare import create_artifact_share from .element_generators import create_element_size, update_element_size from .junction import generate_junction diff --git a/tests/testutils/element_generators.py b/tests/testutils/element_generators.py index 4461e4b7f..ec1b6bd85 100644 --- a/tests/testutils/element_generators.py +++ b/tests/testutils/element_generators.py @@ -2,8 +2,7 @@ import os from buildstream import _yaml from buildstream import utils - -from .repo import create_repo +from buildstream.plugintestutils import create_repo # create_element_size() diff --git a/tests/testutils/junction.py b/tests/testutils/junction.py index e0db8fcfb..49bc692ed 100644 --- a/tests/testutils/junction.py +++ b/tests/testutils/junction.py @@ -1,6 +1,5 @@ from buildstream import _yaml - -from .repo import create_repo +from buildstream.plugintestutils import create_repo # generate_junction() diff --git a/tests/testutils/repo/__init__.py b/tests/testutils/repo/__init__.py index 1881aa3c4..e69de29bb 100644 --- a/tests/testutils/repo/__init__.py +++ b/tests/testutils/repo/__init__.py @@ -1,31 +0,0 @@ -from collections import OrderedDict - -from .git import Git -from .bzr import Bzr -from .ostree import OSTree -from .tar import Tar -from .zip import Zip - -ALL_REPO_KINDS = OrderedDict() -ALL_REPO_KINDS['git'] = Git -ALL_REPO_KINDS['bzr'] = Bzr -ALL_REPO_KINDS['ostree'] = OSTree -ALL_REPO_KINDS['tar'] = Tar -ALL_REPO_KINDS['zip'] = Zip - - -# create_repo() -# -# Convenience for creating a Repo -# -# Args: -# kind (str): The kind of repo to create (a source plugin basename) -# directory (str): The path where the repo will keep a cache -# -def create_repo(kind, directory, subdir='repo'): - try: - constructor = ALL_REPO_KINDS[kind] - except KeyError as e: - raise AssertionError("Unsupported repo kind {}".format(kind)) from e - - return constructor(directory, subdir=subdir) diff --git a/tests/testutils/repo/bzr.py b/tests/testutils/repo/bzr.py index 0bedb3aa7..c006c3fce 100644 --- a/tests/testutils/repo/bzr.py +++ b/tests/testutils/repo/bzr.py @@ -2,7 +2,7 @@ import os import subprocess import pytest -from .repo import Repo +from buildstream.plugintestutils import Repo from .. import site diff --git a/tests/testutils/repo/git.py b/tests/testutils/repo/git.py index 1455de264..5c27be3ee 100644 --- a/tests/testutils/repo/git.py +++ b/tests/testutils/repo/git.py @@ -4,7 +4,7 @@ import subprocess import pytest -from .repo import Repo +from buildstream.plugintestutils import Repo from .. import site diff --git a/tests/testutils/repo/ostree.py b/tests/testutils/repo/ostree.py index 0bb1d8ae3..d0cef8b88 100644 --- a/tests/testutils/repo/ostree.py +++ b/tests/testutils/repo/ostree.py @@ -2,7 +2,7 @@ import subprocess import pytest -from .repo import Repo +from buildstream.plugintestutils import Repo from .. import site diff --git a/tests/testutils/repo/repo.py b/tests/testutils/repo/repo.py deleted file mode 100644 index 234aa374c..000000000 --- a/tests/testutils/repo/repo.py +++ /dev/null @@ -1,90 +0,0 @@ -import os -import shutil - - -# Repo() -# -# Abstract class providing scaffolding for -# generating data to be used with various sources -# -# Args: -# directory (str): The base temp directory for the test -# subdir (str): The subdir for the repo, in case there is more than one -# -class Repo(): - - def __init__(self, directory, subdir='repo'): - - # The working directory for the repo object - # - self.directory = os.path.abspath(directory) - - # The directory the actual repo will be stored in - self.repo = os.path.join(self.directory, subdir) - - os.makedirs(self.repo, exist_ok=True) - - # create(): - # - # Create a repository in self.directory and add the initial content - # - # Args: - # directory: A directory with content to commit - # - # Returns: - # (smth): A new ref corresponding to this commit, which can - # be passed as the ref in the Repo.source_config() API. - # - def create(self, directory): - pass - - # source_config() - # - # Args: - # ref (smth): An optional abstract ref object, usually a string. - # - # Returns: - # (dict): A configuration which can be serialized as a - # source when generating an element file on the fly - # - def source_config(self, ref=None): - pass - - # copy_directory(): - # - # Copies the content of src to the directory dest - # - # Like shutil.copytree(), except dest is expected - # to exist. - # - # Args: - # src (str): The source directory - # dest (str): The destination directory - # - def copy_directory(self, src, dest): - for filename in os.listdir(src): - src_path = os.path.join(src, filename) - dest_path = os.path.join(dest, filename) - if os.path.isdir(src_path): - shutil.copytree(src_path, dest_path) - else: - shutil.copy2(src_path, dest_path) - - # copy(): - # - # Creates a copy of this repository in the specified - # destination. - # - # Args: - # dest (str): The destination directory - # - # Returns: - # (Repo): A Repo object for the new repository. - def copy(self, dest): - subdir = self.repo[len(self.directory):].lstrip(os.sep) - new_dir = os.path.join(dest, subdir) - os.makedirs(new_dir, exist_ok=True) - self.copy_directory(self.repo, new_dir) - repo_type = type(self) - new_repo = repo_type(dest, subdir) - return new_repo diff --git a/tests/testutils/repo/tar.py b/tests/testutils/repo/tar.py index ee6cb77b3..6fdf58ae0 100644 --- a/tests/testutils/repo/tar.py +++ b/tests/testutils/repo/tar.py @@ -3,7 +3,7 @@ import tarfile from buildstream.utils import sha256sum -from .repo import Repo +from buildstream.plugintestutils import Repo class Tar(Repo): diff --git a/tests/testutils/repo/zip.py b/tests/testutils/repo/zip.py index 8133f1236..c57e09e7d 100644 --- a/tests/testutils/repo/zip.py +++ b/tests/testutils/repo/zip.py @@ -3,7 +3,7 @@ import zipfile from buildstream.utils import sha256sum -from .repo import Repo +from buildstream.plugintestutils import Repo class Zip(Repo): @@ -127,3 +127,23 @@ deps = -rrequirements/dev-requirements.txt -rrequirements/plugin-requirements.txt whitelist_externals = * + + +# +# Convenience environment for running individual tests from the +# battery of templated source tests. +# +# You should pass this the part of a test node's id after "::". For +# example, to run the test +# buildstream/plugintestutils/_sourcetests/fetch.py::test_fetch_cross_junction[git-inline] +# you would do tox -e sourcetests -- test_fetch_cross_junction[git-inline] +# +# This does rely on the fact that none of the tests in +# buildstream.plugintestutils have the same name. +# +[testenv:sourcetests] +commands = pytest --basetemp {envtmpdir} --ignore tests -k "{posargs}" +deps = + -rrequirements/requirements.txt + -rrequirements/dev-requirements.txt + -rrequirements/plugin-requirements.txt |