| # 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" |