summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipalib/plugable.py25
-rw-r--r--tests/test_ipalib/test_plugable.py187
2 files changed, 128 insertions, 84 deletions
diff --git a/ipalib/plugable.py b/ipalib/plugable.py
index fd87586d..f0121433 100644
--- a/ipalib/plugable.py
+++ b/ipalib/plugable.py
@@ -707,19 +707,40 @@ class API(DictProxy):
"""
Dynamic API object through which `Plugin` instances are accessed.
"""
- __finalized = False
def __init__(self, *allowed):
self.__d = dict()
+ self.__done = set()
self.register = Registrar(*allowed)
self.env = Environment()
super(API, self).__init__(self.__d)
+ def __doing(self, name):
+ if name in self.__done:
+ raise StandardError(
+ '%s.%s() already called' % (self.__class__.__name__, name)
+ )
+ self.__done.add(name)
+
+ def __do_if_not_done(self, name):
+ if name not in self.__done:
+ getattr(self, name)()
+
+ def isdone(self, name):
+ return name in self.__done
+
+ def bootstrap(self, **overrides):
+ """
+ Initialize environment variables needed by built-in plugins.
+ """
+ self.__doing('bootstrap')
+
def finalize(self):
"""
Finalize the registration, instantiate the plugins.
"""
- assert not self.__finalized, 'finalize() can only be called once'
+ self.__doing('finalize')
+ self.__do_if_not_done('bootstrap')
class PluginInstance(object):
"""
diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py
index 61011797..bdbadae5 100644
--- a/tests/test_ipalib/test_plugable.py
+++ b/tests/test_ipalib/test_plugable.py
@@ -764,99 +764,122 @@ def test_Registrar():
assert issubclass(klass, base)
-def test_API():
+class test_API(ClassChecker):
"""
Test the `ipalib.plugable.API` class.
"""
- assert issubclass(plugable.API, plugable.ReadOnly)
- # Setup the test bases, create the API:
- class base0(plugable.Plugin):
- __public__ = frozenset((
- 'method',
- ))
+ _cls = plugable.API
- def method(self, n):
- return n
+ def test_API(self):
+ """
+ Test the `ipalib.plugable.API` class.
+ """
+ assert issubclass(plugable.API, plugable.ReadOnly)
- class base1(plugable.Plugin):
- __public__ = frozenset((
- 'method',
- ))
+ # Setup the test bases, create the API:
+ class base0(plugable.Plugin):
+ __public__ = frozenset((
+ 'method',
+ ))
- def method(self, n):
- return n + 1
+ def method(self, n):
+ return n
- api = plugable.API(base0, base1)
- r = api.register
- assert isinstance(r, plugable.Registrar)
- assert read_only(api, 'register') is r
+ class base1(plugable.Plugin):
+ __public__ = frozenset((
+ 'method',
+ ))
- class base0_plugin0(base0):
- pass
- r(base0_plugin0)
+ def method(self, n):
+ return n + 1
- class base0_plugin1(base0):
- pass
- r(base0_plugin1)
+ api = plugable.API(base0, base1)
+ r = api.register
+ assert isinstance(r, plugable.Registrar)
+ assert read_only(api, 'register') is r
- class base0_plugin2(base0):
- pass
- r(base0_plugin2)
+ class base0_plugin0(base0):
+ pass
+ r(base0_plugin0)
- class base1_plugin0(base1):
- pass
- r(base1_plugin0)
+ class base0_plugin1(base0):
+ pass
+ r(base0_plugin1)
- class base1_plugin1(base1):
- pass
- r(base1_plugin1)
+ class base0_plugin2(base0):
+ pass
+ r(base0_plugin2)
- class base1_plugin2(base1):
- pass
- r(base1_plugin2)
-
- # Test API instance:
- api.finalize()
-
- def get_base(b):
- return 'base%d' % b
-
- def get_plugin(b, p):
- return 'base%d_plugin%d' % (b, p)
-
- for b in xrange(2):
- base_name = get_base(b)
- ns = getattr(api, base_name)
- assert isinstance(ns, plugable.NameSpace)
- assert read_only(api, base_name) is ns
- assert len(ns) == 3
- for p in xrange(3):
- plugin_name = get_plugin(b, p)
- proxy = ns[plugin_name]
- assert isinstance(proxy, plugable.PluginProxy)
- assert proxy.name == plugin_name
- assert read_only(ns, plugin_name) is proxy
- assert read_only(proxy, 'method')(7) == 7 + b
-
- # Test that calling finilize again raises AssertionError:
- raises(AssertionError, api.finalize)
-
- # Test with base class that doesn't request a proxy
- class NoProxy(plugable.Plugin):
- __proxy__ = False
- api = plugable.API(NoProxy)
- class plugin0(NoProxy):
- pass
- api.register(plugin0)
- class plugin1(NoProxy):
- pass
- api.register(plugin1)
- api.finalize()
- names = ['plugin0', 'plugin1']
- assert list(api.NoProxy) == names
- for name in names:
- plugin = api.NoProxy[name]
- assert getattr(api.NoProxy, name) is plugin
- assert isinstance(plugin, plugable.Plugin)
- assert not isinstance(plugin, plugable.PluginProxy)
+ class base1_plugin0(base1):
+ pass
+ r(base1_plugin0)
+
+ class base1_plugin1(base1):
+ pass
+ r(base1_plugin1)
+
+ class base1_plugin2(base1):
+ pass
+ r(base1_plugin2)
+
+ # Test API instance:
+ assert api.isdone('bootstrap') is False
+ assert api.isdone('finalize') is False
+ api.finalize()
+ assert api.isdone('bootstrap') is True
+ assert api.isdone('finalize') is True
+
+ def get_base(b):
+ return 'base%d' % b
+
+ def get_plugin(b, p):
+ return 'base%d_plugin%d' % (b, p)
+
+ for b in xrange(2):
+ base_name = get_base(b)
+ ns = getattr(api, base_name)
+ assert isinstance(ns, plugable.NameSpace)
+ assert read_only(api, base_name) is ns
+ assert len(ns) == 3
+ for p in xrange(3):
+ plugin_name = get_plugin(b, p)
+ proxy = ns[plugin_name]
+ assert isinstance(proxy, plugable.PluginProxy)
+ assert proxy.name == plugin_name
+ assert read_only(ns, plugin_name) is proxy
+ assert read_only(proxy, 'method')(7) == 7 + b
+
+ # Test that calling finilize again raises AssertionError:
+ e = raises(StandardError, api.finalize)
+ assert str(e) == 'API.finalize() already called', str(e)
+
+ # Test with base class that doesn't request a proxy
+ class NoProxy(plugable.Plugin):
+ __proxy__ = False
+ api = plugable.API(NoProxy)
+ class plugin0(NoProxy):
+ pass
+ api.register(plugin0)
+ class plugin1(NoProxy):
+ pass
+ api.register(plugin1)
+ api.finalize()
+ names = ['plugin0', 'plugin1']
+ assert list(api.NoProxy) == names
+ for name in names:
+ plugin = api.NoProxy[name]
+ assert getattr(api.NoProxy, name) is plugin
+ assert isinstance(plugin, plugable.Plugin)
+ assert not isinstance(plugin, plugable.PluginProxy)
+
+ def test_bootstrap(self):
+ """
+ Test the `ipalib.plugable.API.bootstrap` method.
+ """
+ o = self.cls()
+ assert o.isdone('bootstrap') is False
+ o.bootstrap()
+ assert o.isdone('bootstrap') is True
+ e = raises(StandardError, o.bootstrap)
+ assert str(e) == 'API.bootstrap() already called'