freeipa/ipatests/test_ipalib/test_plugable.py
Rob Crittenden 4a89da5352 ipatests: Add option/arg parsing tests for the cli
A typo in passing in options would result in an exception.

For example -verbose was treated as: -v -e rbose

-v and -e are valid options. rbose on its own has no value in the
name-value pair so an exception would result.

https://pagure.io/freeipa/issue/6115

Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2020-08-25 10:31:19 -04:00

346 lines
10 KiB
Python

# Authors:
# Jason Gerard DeRose <jderose@redhat.com>
#
# Copyright (C) 2008 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.plugable` module.
"""
# FIXME: Pylint errors
# pylint: disable=no-member
import os
import sys
import textwrap
from ipalib import plugable, errors, create_api
from ipatests.util import raises, read_only
from ipatests.util import ClassChecker, create_test_api, TempHome
import pytest
pytestmark = pytest.mark.tier0
class test_Plugin(ClassChecker):
"""
Test the `ipalib.plugable.Plugin` class.
"""
_cls = plugable.Plugin
def test_class(self):
"""
Test the `ipalib.plugable.Plugin` class.
"""
assert self.cls.__bases__ == (plugable.ReadOnly,)
assert type(self.cls.api) is property
def test_init(self):
"""
Test the `ipalib.plugable.Plugin.__init__` method.
"""
api = 'the api instance'
o = self.cls(api)
assert o.name == 'Plugin'
assert isinstance(o.doc, str)
class some_subclass(self.cls):
"""
Do sub-classy things.
Although it doesn't know how to comport itself and is not for mixed
company, this class *is* useful as we all need a little sub-class
now and then.
One more paragraph.
"""
o = some_subclass(api)
assert o.name == 'some_subclass'
assert o.summary == 'Do sub-classy things.'
assert isinstance(o.doc, str)
class another_subclass(self.cls):
pass
o = another_subclass(api)
assert o.summary == u'<%s.%s>' % (another_subclass.__module__,
another_subclass.__name__)
def test_finalize(self):
"""
Test the `ipalib.plugable.Plugin.finalize` method.
"""
class api:
@staticmethod
def is_production_mode():
return False
o = self.cls(api)
assert not o.__islocked__()
o.finalize()
assert o.__islocked__()
def test_Registry():
"""
Test the `ipalib.plugable.Registry` class
"""
class Base1:
pass
class Base2:
pass
class plugin1(Base1):
pass
class plugin2(Base2):
pass
# Test creation of Registry:
r = plugable.Registry()
# Check that TypeError is raised trying to register something that isn't
# a class:
p = plugin1()
e = raises(TypeError, r(), p)
assert str(e) == 'plugin must be callable; got %r' % p
# Check that registration works
r()(plugin1)
# Check that DuplicateError is raised trying to register exact class
# again:
e = raises(errors.PluginDuplicateError, r(), plugin1)
assert e.plugin is plugin1
# Check that overriding works
class base1_extended(Base1):
pass
class plugin1(base1_extended): # pylint: disable=function-redefined
pass
r(override=True)(plugin1)
# Test that another plugin can be registered:
r()(plugin2)
# Setup to test more registration:
class plugin1a(Base1):
pass
r()(plugin1a)
class plugin1b(Base1):
pass
r()(plugin1b)
class plugin2a(Base2):
pass
r()(plugin2a)
class plugin2b(Base2):
pass
r()(plugin2b)
class test_API(ClassChecker):
"""
Test the `ipalib.plugable.API` class.
"""
_cls = plugable.API
def test_API(self):
"""
Test the `ipalib.plugable.API` class.
"""
assert issubclass(plugable.API, plugable.ReadOnly)
# Setup the test bases, create the API:
class base0(plugable.Plugin):
def method(self, n):
return n
class base1(plugable.Plugin):
def method(self, n):
return n + 1
class API(plugable.API):
bases = (base0, base1)
modules = ()
api = API()
api.env.mode = 'unit_test'
api.env.in_tree = True
r = api.add_plugin
class base0_plugin0(base0):
pass
r(base0_plugin0)
class base0_plugin1(base0):
pass
r(base0_plugin1)
class base0_plugin2(base0):
pass
r(base0_plugin2)
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_name(b):
return 'base%d' % b
def get_plugin_name(b, p):
return 'base%d_plugin%d' % (b, p)
for b in range(2):
base_name = get_base_name(b)
base = locals()[base_name]
ns = getattr(api, base_name)
assert isinstance(ns, plugable.APINameSpace)
assert read_only(api, base_name) is ns
assert len(ns) == 3
for p in range(3):
plugin_name = get_plugin_name(b, p)
plugin = locals()[plugin_name]
inst = ns[plugin_name]
assert isinstance(inst, base)
assert isinstance(inst, plugin)
assert inst.name == plugin_name
assert inst.method(7) == 7 + b
# Test that calling finilize again raises AssertionError:
e = raises(Exception, api.finalize)
assert str(e) == 'API.finalize() already called', str(e)
def test_bootstrap(self):
"""
Test the `ipalib.plugable.API.bootstrap` method.
"""
o, _home = create_test_api()
assert o.env._isdone('_bootstrap') is False
assert o.env._isdone('_finalize_core') is False
assert o.isdone('bootstrap') is False
o.bootstrap(my_test_override='Hello, world!')
assert o.isdone('bootstrap') is True
assert o.env._isdone('_bootstrap') is True
assert o.env._isdone('_finalize_core') is True
assert o.env.my_test_override == 'Hello, world!'
e = raises(Exception, o.bootstrap)
assert str(e) == 'API.bootstrap() already called'
def test_load_plugins(self):
"""
Test the `ipalib.plugable.API.load_plugins` method.
"""
o, _home = create_test_api()
assert o.isdone('bootstrap') is False
assert o.isdone('load_plugins') is False
o.load_plugins()
assert o.isdone('bootstrap') is True
assert o.isdone('load_plugins') is True
e = raises(Exception, o.load_plugins)
assert str(e) == 'API.load_plugins() already called'
def test_ipaconf_env(self):
ipa_confdir = os.environ.get('IPA_CONFDIR', None)
try:
with TempHome() as home:
defaultconf = home.join('default.conf')
with open(defaultconf, 'w') as f:
f.write(textwrap.dedent("""
[global]
basedn = dc=ipa,dc=test
realm = IPA.TEST
domain = ipa.test
""")
)
os.environ['IPA_CONFDIR'] = home.path
api = create_api(mode='unit_test')
api.bootstrap()
api.finalize()
assert api.env.confdir == home.path
assert api.env.conf_default == defaultconf
assert api.env.realm == 'IPA.TEST'
assert api.env.domain == 'ipa.test'
os.environ['IPA_CONFDIR'] = home.join('invalid')
api = create_api(mode='unit_test')
with pytest.raises(errors.EnvironmentError):
api.bootstrap()
finally:
if ipa_confdir:
os.environ['IPA_CONFDIR'] = ipa_confdir
else:
os.environ.pop('IPA_CONFDIR')
class test_cli(ClassChecker):
"""
Test the `ipalib.plugable` global bootstrap.
"""
def test_no_args(self):
sys.argv = ['/usr/bin/ipa']
api = create_api(mode='unit_test')
(_options, argv) = api.bootstrap_with_global_options(
context='unit_test')
assert len(argv) == 0
assert _options.env is None
assert _options.conf is None
assert _options.debug is None
assert _options.delegate is None
assert _options.verbose is None
def test_one_arg(self):
sys.argv = ['/usr/bin/ipa', 'user-show']
api = create_api(mode='unit_test')
(_options, argv) = api.bootstrap_with_global_options(
context='unit_test')
assert argv == ['user-show']
assert _options.verbose is None
def test_args_valid_option(self):
sys.argv = ['/usr/bin/ipa', '-v', 'user-show']
api = create_api(mode='unit_test')
(_options, argv) = api.bootstrap_with_global_options(
context='unit_test')
assert argv == ['user-show']
assert _options.verbose == 1
def test_args_invalid_option(self):
sys.argv = ['/usr/bin/ipa', '-verbose', 'user-show']
api = create_api(mode='unit_test')
try:
api.bootstrap_with_global_options(context='unit_test')
except errors.OptionError as e:
assert e.msg == 'Unable to parse option rbose'