blob: 13b9d3aae818867f5a1023713492debe967bd2ea [file] [log] [blame]
# Pylint doesn't play well with fixtures and dependency injection from pytest
# pylint: disable=redefined-outer-name
import os
import pytest
from pluginbase import PluginBase
from buildstream import Node
from buildstream._elementfactory import ElementFactory
from buildstream._sourcefactory import SourceFactory
from buildstream._exceptions import PluginError
DATA_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "pluginfactory",)
# Simple fixture to create a PluginBase object that
# we use for loading plugins.
@pytest.fixture()
def plugin_fixture():
return {"base": PluginBase(package="buildstream.plugins")}
##############################################################
# Basics: test the fixture, test we can create the factories #
##############################################################
def test_fixture(plugin_fixture):
assert isinstance(plugin_fixture["base"], PluginBase)
def test_source_factory(plugin_fixture):
factory = SourceFactory(plugin_fixture["base"])
assert isinstance(factory, SourceFactory)
def test_element_factory(plugin_fixture):
factory = ElementFactory(plugin_fixture["base"])
assert isinstance(factory, ElementFactory)
##############################################################
# Check that we can load custom sources & elements #
##############################################################
@pytest.mark.datafiles(os.path.join(DATA_DIR, "customsource"))
def test_custom_source(plugin_fixture, datafiles):
plugins = [
Node.from_dict(
{"origin": "local", "path": os.path.join(datafiles.dirname, datafiles.basename), "plugins": ["foo"]}
)
]
factory = SourceFactory(plugin_fixture["base"], plugin_origins=plugins)
assert isinstance(factory, SourceFactory)
foo_type, _ = factory.lookup("foo")
assert foo_type.__name__ == "FooSource"
@pytest.mark.datafiles(os.path.join(DATA_DIR, "customelement"))
def test_custom_element(plugin_fixture, datafiles):
plugins = [
Node.from_dict(
{"origin": "local", "path": os.path.join(datafiles.dirname, datafiles.basename), "plugins": ["foo"]}
)
]
factory = ElementFactory(plugin_fixture["base"], plugin_origins=plugins)
assert isinstance(factory, ElementFactory)
foo_type, _ = factory.lookup("foo")
assert foo_type.__name__ == "FooElement"
##############################################################
# Check plugin loading failure modes #
##############################################################
def test_missing_source(plugin_fixture):
factory = SourceFactory(plugin_fixture["base"])
assert isinstance(factory, SourceFactory)
# Test fails if PluginError is not raised
with pytest.raises(PluginError):
factory.lookup("foo")
def test_missing_element(plugin_fixture):
factory = ElementFactory(plugin_fixture["base"])
assert isinstance(factory, ElementFactory)
# Test fails if PluginError is not raised
with pytest.raises(PluginError):
factory.lookup("foo")
# Load a factory with a plugin that returns a value instead of Source subclass
@pytest.mark.datafiles(os.path.join(DATA_DIR, "notatype"))
def test_source_notatype(plugin_fixture, datafiles):
plugins = [
Node.from_dict(
{"origin": "local", "path": os.path.join(datafiles.dirname, datafiles.basename), "plugins": ["foo"]}
)
]
factory = SourceFactory(plugin_fixture["base"], plugin_origins=plugins)
with pytest.raises(PluginError):
factory.lookup("foo")
# Load a factory with a plugin that returns a value instead of Element subclass
@pytest.mark.datafiles(os.path.join(DATA_DIR, "notatype"))
def test_element_notatype(plugin_fixture, datafiles):
plugins = [
Node.from_dict(
{"origin": "local", "path": os.path.join(datafiles.dirname, datafiles.basename), "plugins": ["foo"]}
)
]
factory = ElementFactory(plugin_fixture["base"], plugin_origins=plugins)
with pytest.raises(PluginError):
factory.lookup("foo")
# Load a factory with a plugin that returns a type
# which is not a Source subclass
@pytest.mark.datafiles(os.path.join(DATA_DIR, "wrongtype"))
def test_source_wrongtype(plugin_fixture, datafiles):
plugins = [
Node.from_dict(
{"origin": "local", "path": os.path.join(datafiles.dirname, datafiles.basename), "plugins": ["foo"]}
)
]
factory = SourceFactory(plugin_fixture["base"], plugin_origins=plugins)
with pytest.raises(PluginError):
factory.lookup("foo")
# Load a factory with a plugin that returns a type
# which is not a Element subclass
@pytest.mark.datafiles(os.path.join(DATA_DIR, "wrongtype"))
def test_element_wrongtype(plugin_fixture, datafiles):
plugins = [
Node.from_dict(
{"origin": "local", "path": os.path.join(datafiles.dirname, datafiles.basename), "plugins": ["foo"]}
)
]
factory = ElementFactory(plugin_fixture["base"], plugin_origins=plugins)
with pytest.raises(PluginError):
factory.lookup("foo")
# Load a factory with a plugin which fails to provide a setup() function
@pytest.mark.datafiles(os.path.join(DATA_DIR, "nosetup"))
def test_source_missing_setup(plugin_fixture, datafiles):
plugins = [
Node.from_dict(
{"origin": "local", "path": os.path.join(datafiles.dirname, datafiles.basename), "plugins": ["foo"]}
)
]
factory = SourceFactory(plugin_fixture["base"], plugin_origins=plugins)
with pytest.raises(PluginError):
factory.lookup("foo")
# Load a factory with a plugin which fails to provide a setup() function
@pytest.mark.datafiles(os.path.join(DATA_DIR, "nosetup"))
def test_element_missing_setup(plugin_fixture, datafiles):
plugins = [
Node.from_dict(
{"origin": "local", "path": os.path.join(datafiles.dirname, datafiles.basename), "plugins": ["foo"]}
)
]
factory = ElementFactory(plugin_fixture["base"], plugin_origins=plugins)
with pytest.raises(PluginError):
factory.lookup("foo")
# Load a factory with a plugin which provides a setup symbol
# that is not a function
@pytest.mark.datafiles(os.path.join(DATA_DIR, "badsetup"))
def test_source_bad_setup(plugin_fixture, datafiles):
plugins = [
Node.from_dict(
{"origin": "local", "path": os.path.join(datafiles.dirname, datafiles.basename), "plugins": ["foo"]}
)
]
factory = SourceFactory(plugin_fixture["base"], plugin_origins=plugins)
with pytest.raises(PluginError):
factory.lookup("foo")
# Load a factory with a plugin which provides a setup symbol
# that is not a function
@pytest.mark.datafiles(os.path.join(DATA_DIR, "badsetup"))
def test_element_bad_setup(plugin_fixture, datafiles):
plugins = [
Node.from_dict(
{"origin": "local", "path": os.path.join(datafiles.dirname, datafiles.basename), "plugins": ["foo"]}
)
]
factory = ElementFactory(plugin_fixture["base"], plugin_origins=plugins)
with pytest.raises(PluginError):
factory.lookup("foo")
# Load a factory with a plugin which requires an absurdly
# high version of buildstream
@pytest.mark.datafiles(os.path.join(DATA_DIR, "badversionsource"))
def test_source_badversion(plugin_fixture, datafiles):
plugins = [
Node.from_dict(
{"origin": "local", "path": os.path.join(datafiles.dirname, datafiles.basename), "plugins": ["foo"]}
)
]
factory = SourceFactory(plugin_fixture["base"], plugin_origins=plugins)
with pytest.raises(PluginError):
factory.lookup("foo")
# Load a factory with a plugin which requires an absurdly
# high version of buildstream
@pytest.mark.datafiles(os.path.join(DATA_DIR, "badversionelement"))
def test_element_badversion(plugin_fixture, datafiles):
plugins = [
Node.from_dict(
{"origin": "local", "path": os.path.join(datafiles.dirname, datafiles.basename), "plugins": ["foo"]}
)
]
factory = ElementFactory(plugin_fixture["base"], plugin_origins=plugins)
with pytest.raises(PluginError):
factory.lookup("foo")
##############################################################
# Check we can load different contexts of plugin #
##############################################################
# Load two factories, both of which define a different 'foo' plugin
@pytest.mark.datafiles(DATA_DIR)
def test_source_multicontext(plugin_fixture, datafiles):
plugins1 = Node.from_dict(
{
"origin": "local",
"path": os.path.join(datafiles.dirname, datafiles.basename, "customsource"),
"plugins": ["foo"],
}
)
plugins2 = Node.from_dict(
{
"origin": "local",
"path": os.path.join(datafiles.dirname, datafiles.basename, "anothersource"),
"plugins": ["foo"],
}
)
factory1 = SourceFactory(plugin_fixture["base"], plugin_origins=[plugins1])
factory2 = SourceFactory(plugin_fixture["base"], plugin_origins=[plugins2])
assert isinstance(factory1, SourceFactory)
assert isinstance(factory2, SourceFactory)
foo_type1, _ = factory1.lookup("foo")
foo_type2, _ = factory2.lookup("foo")
assert foo_type1.__name__ == "FooSource"
assert foo_type2.__name__ == "AnotherFooSource"
# Load two factories, both of which define a different 'foo' plugin
@pytest.mark.datafiles(DATA_DIR)
def test_element_multicontext(plugin_fixture, datafiles):
plugins1 = Node.from_dict(
{
"origin": "local",
"path": os.path.join(datafiles.dirname, datafiles.basename, "customelement"),
"plugins": ["foo"],
}
)
plugins2 = Node.from_dict(
{
"origin": "local",
"path": os.path.join(datafiles.dirname, datafiles.basename, "anotherelement"),
"plugins": ["foo"],
}
)
factory1 = ElementFactory(plugin_fixture["base"], plugin_origins=[plugins1])
factory2 = ElementFactory(plugin_fixture["base"], plugin_origins=[plugins2])
assert isinstance(factory1, ElementFactory)
assert isinstance(factory2, ElementFactory)
foo_type1, _ = factory1.lookup("foo")
foo_type2, _ = factory2.lookup("foo")
assert foo_type1.__name__ == "FooElement"
assert foo_type2.__name__ == "AnotherFooElement"