blob: e9e63672f75e9f53631852e5f866e83f0a07b002 [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._elementfactory import ElementFactory
from buildstream._sourcefactory import SourceFactory
from buildstream._exceptions import PluginError
from buildstream import _yaml
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 = [_yaml.new_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 = [_yaml.new_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 = [_yaml.new_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 = [_yaml.new_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 = [_yaml.new_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 = [_yaml.new_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 = [_yaml.new_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 = [_yaml.new_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 = [_yaml.new_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 = [_yaml.new_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 = [_yaml.new_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 = [_yaml.new_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 = _yaml.new_node_from_dict({
'origin': 'local',
'path': os.path.join(datafiles.dirname,
datafiles.basename,
'customsource'),
'plugins': ['foo']
})
plugins2 = _yaml.new_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 = _yaml.new_node_from_dict({
'origin': 'local',
'path': os.path.join(datafiles.dirname,
datafiles.basename,
'customelement'),
'plugins': ['foo']
})
plugins2 = _yaml.new_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'