summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbst-marge-bot <marge-bot@buildstream.build>2019-04-15 09:00:51 +0000
committerbst-marge-bot <marge-bot@buildstream.build>2019-04-15 09:00:51 +0000
commitb9eec0cadcc05d1d791beb4a1411400c19bedb0b (patch)
treeb5f9ccc6ec40fc765e741957b614646511ff54ef
parent92c9a04747a9773c0036578db9cb3fa9acb12247 (diff)
parentc90cf9e8680350a75f4a76b464fdf7fe4dab4016 (diff)
downloadbuildstream-b9eec0cadcc05d1d791beb4a1411400c19bedb0b.tar.gz
Merge branch 'phil/expose-templated-tests' into 'master'
Expose templated source tests See merge request BuildStream/buildstream!1261
-rw-r--r--MANIFEST.in3
-rw-r--r--buildstream/plugintestutils/__init__.py68
-rw-r--r--buildstream/plugintestutils/_sourcetests/__init__.py (renamed from tests/sources/generic/__init__.py)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/build_checkout.py (renamed from tests/sources/generic/build_checkout.py)3
-rw-r--r--buildstream/plugintestutils/_sourcetests/fetch.py (renamed from tests/sources/generic/fetch.py)8
-rw-r--r--buildstream/plugintestutils/_sourcetests/mirror.py (renamed from tests/sources/generic/mirror.py)6
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/base.bst (renamed from tests/sources/generic/project/elements/base.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/base/base-alpine.bst (renamed from tests/sources/generic/project/elements/base/base-alpine.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/import-bin.bst (renamed from tests/sources/generic/project/elements/import-bin.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/import-dev.bst (renamed from tests/sources/generic/project/elements/import-dev.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/dependency/horsey.bst (renamed from tests/sources/generic/project/elements/multiple_targets/dependency/horsey.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/dependency/pony.bst (renamed from tests/sources/generic/project/elements/multiple_targets/dependency/pony.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/dependency/zebry.bst (renamed from tests/sources/generic/project/elements/multiple_targets/dependency/zebry.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/0.bst (renamed from tests/sources/generic/project/elements/multiple_targets/order/0.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/1.bst (renamed from tests/sources/generic/project/elements/multiple_targets/order/1.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/2.bst (renamed from tests/sources/generic/project/elements/multiple_targets/order/2.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/3.bst (renamed from tests/sources/generic/project/elements/multiple_targets/order/3.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/4.bst (renamed from tests/sources/generic/project/elements/multiple_targets/order/4.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/5.bst (renamed from tests/sources/generic/project/elements/multiple_targets/order/5.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/6.bst (renamed from tests/sources/generic/project/elements/multiple_targets/order/6.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/7.bst (renamed from tests/sources/generic/project/elements/multiple_targets/order/7.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/8.bst (renamed from tests/sources/generic/project/elements/multiple_targets/order/8.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/9.bst (renamed from tests/sources/generic/project/elements/multiple_targets/order/9.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/elements/multiple_targets/order/run.bst (renamed from tests/sources/generic/project/elements/multiple_targets/order/run.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/files/bar (renamed from tests/sources/generic/project/files/bar)0
-rwxr-xr-xbuildstream/plugintestutils/_sourcetests/project/files/bin-files/usr/bin/hello (renamed from tests/sources/generic/project/files/bin-files/usr/bin/hello)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/files/dev-files/usr/include/pony.h (renamed from tests/sources/generic/project/files/dev-files/usr/include/pony.h)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/files/etc-files/etc/buildstream/config (renamed from tests/sources/generic/project/files/etc-files/etc/buildstream/config)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/files/foo (renamed from tests/sources/generic/project/files/foo)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/files/source-bundle/llamas.txt (renamed from tests/sources/generic/project/files/source-bundle/llamas.txt)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/files/sub-project/elements/import-etc.bst (renamed from tests/sources/generic/project/files/sub-project/elements/import-etc.bst)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/files/sub-project/files/etc-files/etc/animal.conf (renamed from tests/sources/generic/project/files/sub-project/files/etc-files/etc/animal.conf)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/files/sub-project/project.conf (renamed from tests/sources/generic/project/files/sub-project/project.conf)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/project/project.conf (renamed from tests/sources/generic/project/project.conf)0
-rw-r--r--buildstream/plugintestutils/_sourcetests/source_determinism.py (renamed from tests/sources/generic/source_determinism.py)7
-rw-r--r--buildstream/plugintestutils/_sourcetests/track.py (renamed from tests/sources/generic/track.py)8
-rw-r--r--buildstream/plugintestutils/_sourcetests/track_cross_junction.py (renamed from tests/sources/generic/track_cross_junction.py)6
-rw-r--r--buildstream/plugintestutils/_sourcetests/workspace.py (renamed from tests/sources/generic/workspace.py)5
-rw-r--r--buildstream/plugintestutils/_utils/__init__.py10
-rw-r--r--buildstream/plugintestutils/_utils/junction.py83
-rw-r--r--buildstream/plugintestutils/_utils/site.py46
-rw-r--r--buildstream/plugintestutils/repo.py109
-rw-r--r--doc/source/core_framework.rst1
-rwxr-xr-xsetup.py1
-rwxr-xr-xtests/conftest.py25
-rw-r--r--tests/elements/filter.py2
-rw-r--r--tests/format/include.py4
-rw-r--r--tests/format/junctions.py2
-rw-r--r--tests/frontend/buildtrack.py3
-rw-r--r--tests/frontend/cross_junction_workspace.py3
-rw-r--r--tests/frontend/fetch.py4
-rw-r--r--tests/frontend/logging.py2
-rw-r--r--tests/frontend/mirror.py3
-rw-r--r--tests/frontend/order.py2
-rw-r--r--tests/frontend/track.py4
-rw-r--r--tests/frontend/workspace.py4
-rw-r--r--tests/integration/source-determinism.py2
-rw-r--r--tests/sourcecache/fetch.py4
-rw-r--r--tests/sourcecache/push.py3
-rw-r--r--tests/sources/bzr.py2
-rw-r--r--tests/sources/git.py2
-rw-r--r--tests/sources/no_fetch_cached.py2
-rw-r--r--tests/sources/ostree.py3
-rw-r--r--tests/testutils/__init__.py1
-rw-r--r--tests/testutils/element_generators.py3
-rw-r--r--tests/testutils/junction.py3
-rw-r--r--tests/testutils/repo/__init__.py31
-rw-r--r--tests/testutils/repo/bzr.py2
-rw-r--r--tests/testutils/repo/git.py2
-rw-r--r--tests/testutils/repo/ostree.py2
-rw-r--r--tests/testutils/repo/repo.py90
-rw-r--r--tests/testutils/repo/tar.py2
-rw-r--r--tests/testutils/repo/zip.py2
-rw-r--r--tox.ini20
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
diff --git a/setup.py b/setup.py
index 49b115453..0154b4ec5 100755
--- a/setup.py
+++ b/setup.py
@@ -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):
diff --git a/tox.ini b/tox.ini
index d708694b0..82e0f13ee 100644
--- a/tox.ini
+++ b/tox.ini
@@ -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