freeipa/tests/test_ipalib/test_frontend.py
Jan Cholasta e7a6d10555 Finalize plugin initialization on demand.
This patch changes the way plugins are initialized. Instead of
finalizing all the plugins at once, plugins are finalized only after
they are accessed (currently applies to Command, Object and
Attribute subclasses, only in CLI by default).

This change provides significant performance boost, as only the
plugins that are actually used are finalized.

ticket 1336
2011-11-22 00:52:24 -05:00

1123 lines
36 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.frontend` module.
"""
from tests.util import raises, getitem, no_set, no_del, read_only
from tests.util import check_TypeError, ClassChecker, create_test_api
from tests.util import assert_equal
from ipalib.constants import TYPE_ERROR
from ipalib.base import NameSpace
from ipalib import frontend, backend, plugable, errors, parameters, config
from ipalib import output
from ipalib.parameters import Str
from ipapython.version import API_VERSION
def test_RULE_FLAG():
assert frontend.RULE_FLAG == 'validation_rule'
def test_rule():
"""
Test the `ipalib.frontend.rule` function.
"""
flag = frontend.RULE_FLAG
rule = frontend.rule
def my_func():
pass
assert not hasattr(my_func, flag)
rule(my_func)
assert getattr(my_func, flag) is True
@rule
def my_func2():
pass
assert getattr(my_func2, flag) is True
def test_is_rule():
"""
Test the `ipalib.frontend.is_rule` function.
"""
is_rule = frontend.is_rule
flag = frontend.RULE_FLAG
class no_call(object):
def __init__(self, value):
if value is not None:
assert value in (True, False)
setattr(self, flag, value)
class call(no_call):
def __call__(self):
pass
assert is_rule(call(True))
assert not is_rule(no_call(True))
assert not is_rule(call(False))
assert not is_rule(call(None))
class test_HasParam(ClassChecker):
"""
Test the `ipalib.frontend.Command` class.
"""
_cls = frontend.HasParam
def test_get_param_iterable(self):
"""
Test the `ipalib.frontend.HasParam._get_param_iterable` method.
"""
class WithTuple(self.cls):
takes_stuff = ('one', 'two')
o = WithTuple()
assert o._get_param_iterable('stuff') is WithTuple.takes_stuff
junk = ('three', 'four')
class WithCallable(self.cls):
def takes_stuff(self):
return junk
o = WithCallable()
assert o._get_param_iterable('stuff') is junk
class WithParam(self.cls):
takes_stuff = parameters.Str('five')
o = WithParam()
assert o._get_param_iterable('stuff') == (WithParam.takes_stuff,)
class WithStr(self.cls):
takes_stuff = 'six'
o = WithStr()
assert o._get_param_iterable('stuff') == ('six',)
class Wrong(self.cls):
takes_stuff = ['seven', 'eight']
o = Wrong()
e = raises(TypeError, o._get_param_iterable, 'stuff')
assert str(e) == '%s.%s must be a tuple, callable, or spec; got %r' % (
'Wrong', 'takes_stuff', Wrong.takes_stuff
)
def test_filter_param_by_context(self):
"""
Test the `ipalib.frontend.HasParam._filter_param_by_context` method.
"""
class Example(self.cls):
def get_stuff(self):
return (
'one', # Make sure create_param() is called for each spec
'two',
parameters.Str('three', include='cli'),
parameters.Str('four', exclude='server'),
parameters.Str('five', exclude=['whatever', 'cli']),
)
o = Example()
# Test when env is None:
params = list(o._filter_param_by_context('stuff'))
assert list(p.name for p in params) == [
'one', 'two', 'three', 'four', 'five'
]
for p in params:
assert type(p) is parameters.Str
# Test when env.context == 'cli':
cli = config.Env(context='cli')
assert cli.context == 'cli'
params = list(o._filter_param_by_context('stuff', cli))
assert list(p.name for p in params) == ['one', 'two', 'three', 'four']
for p in params:
assert type(p) is parameters.Str
# Test when env.context == 'server'
server = config.Env(context='server')
assert server.context == 'server'
params = list(o._filter_param_by_context('stuff', server))
assert list(p.name for p in params) == ['one', 'two', 'five']
for p in params:
assert type(p) is parameters.Str
# Test with no get_stuff:
class Missing(self.cls):
pass
o = Missing()
gen = o._filter_param_by_context('stuff')
e = raises(NotImplementedError, list, gen)
assert str(e) == 'Missing.get_stuff()'
# Test when get_stuff is not callable:
class NotCallable(self.cls):
get_stuff = ('one', 'two')
o = NotCallable()
gen = o._filter_param_by_context('stuff')
e = raises(TypeError, list, gen)
assert str(e) == '%s.%s must be a callable; got %r' % (
'NotCallable', 'get_stuff', NotCallable.get_stuff
)
class test_Command(ClassChecker):
"""
Test the `ipalib.frontend.Command` class.
"""
_cls = frontend.Command
def get_subcls(self):
"""
Return a standard subclass of `ipalib.frontend.Command`.
"""
class Rule(object):
def __init__(self, name):
self.name = name
def __call__(self, _, value):
if value != self.name:
return _('must equal %r') % self.name
default_from = parameters.DefaultFrom(
lambda arg: arg,
'default_from'
)
normalizer = lambda value: value.lower()
class example(self.cls):
takes_options = (
parameters.Str('option0', Rule('option0'),
normalizer=normalizer,
default_from=default_from,
),
parameters.Str('option1', Rule('option1'),
normalizer=normalizer,
default_from=default_from,
),
)
return example
def get_instance(self, args=tuple(), options=tuple()):
"""
Helper method used to test args and options.
"""
class example(self.cls):
takes_args = args
takes_options = options
o = example()
o.finalize()
return o
def test_class(self):
"""
Test the `ipalib.frontend.Command` class.
"""
assert self.cls.takes_options == tuple()
assert self.cls.takes_args == tuple()
def test_get_args(self):
"""
Test the `ipalib.frontend.Command.get_args` method.
"""
assert list(self.cls().get_args()) == []
args = ('login', 'stuff')
o = self.get_instance(args=args)
assert tuple(o.get_args()) == args
def test_get_options(self):
"""
Test the `ipalib.frontend.Command.get_options` method.
"""
assert list(self.cls().get_options()) == []
options = ('verbose', 'debug')
o = self.get_instance(options=options)
assert tuple(o.get_options()) == options
def test_args(self):
"""
Test the ``ipalib.frontend.Command.args`` instance attribute.
"""
assert self.cls().args is None
o = self.cls()
o.finalize()
assert type(o.args) is plugable.NameSpace
assert len(o.args) == 0
args = ('destination', 'source?')
ns = self.get_instance(args=args).args
assert type(ns) is plugable.NameSpace
assert len(ns) == len(args)
assert list(ns) == ['destination', 'source']
assert type(ns.destination) is parameters.Str
assert type(ns.source) is parameters.Str
assert ns.destination.required is True
assert ns.destination.multivalue is False
assert ns.source.required is False
assert ns.source.multivalue is False
# Test TypeError:
e = raises(TypeError, self.get_instance, args=(u'whatever',))
assert str(e) == TYPE_ERROR % (
'spec', (str, parameters.Param), u'whatever', unicode)
# Test ValueError, required after optional:
e = raises(ValueError, self.get_instance, args=('arg1?', 'arg2'))
assert str(e) == 'arg2: required argument after optional'
# Test ValueError, scalar after multivalue:
e = raises(ValueError, self.get_instance, args=('arg1+', 'arg2'))
assert str(e) == 'arg2: only final argument can be multivalue'
def test_max_args(self):
"""
Test the ``ipalib.frontend.Command.max_args`` instance attribute.
"""
o = self.get_instance()
assert o.max_args == 0
o = self.get_instance(args=('one?',))
assert o.max_args == 1
o = self.get_instance(args=('one', 'two?'))
assert o.max_args == 2
o = self.get_instance(args=('one', 'multi+',))
assert o.max_args is None
o = self.get_instance(args=('one', 'multi*',))
assert o.max_args is None
def test_options(self):
"""
Test the ``ipalib.frontend.Command.options`` instance attribute.
"""
assert self.cls().options is None
o = self.cls()
o.finalize()
assert type(o.options) is plugable.NameSpace
assert len(o.options) == 0
options = ('target', 'files*')
ns = self.get_instance(options=options).options
assert type(ns) is plugable.NameSpace
assert len(ns) == len(options)
assert list(ns) == ['target', 'files']
assert type(ns.target) is parameters.Str
assert type(ns.files) is parameters.Str
assert ns.target.required is True
assert ns.target.multivalue is False
assert ns.files.required is False
assert ns.files.multivalue is True
def test_output(self):
"""
Test the ``ipalib.frontend.Command.output`` instance attribute.
"""
inst = self.cls()
assert inst.output is None
inst.finalize()
assert type(inst.output) is plugable.NameSpace
assert list(inst.output) == ['result']
assert type(inst.output.result) is output.Output
def test_iter_output(self):
"""
Test the ``ipalib.frontend.Command._iter_output`` instance attribute.
"""
class Example(self.cls):
pass
inst = Example()
inst.has_output = tuple()
assert list(inst._iter_output()) == []
wrong = ['hello', 'world']
inst.has_output = wrong
e = raises(TypeError, list, inst._iter_output())
assert str(e) == 'Example.has_output: need a %r; got a %r: %r' % (
tuple, list, wrong
)
wrong = ('hello', 17)
inst.has_output = wrong
e = raises(TypeError, list, inst._iter_output())
assert str(e) == 'Example.has_output[1]: need a %r; got a %r: %r' % (
(str, output.Output), int, 17
)
okay = ('foo', output.Output('bar'), 'baz')
inst.has_output = okay
items = list(inst._iter_output())
assert len(items) == 3
assert list(o.name for o in items) == ['foo', 'bar', 'baz']
for o in items:
assert type(o) is output.Output
def test_soft_validate(self):
"""
Test the `ipalib.frontend.Command.soft_validate` method.
"""
class user_add(frontend.Command):
takes_args = parameters.Str('uid',
normalizer=lambda value: value.lower(),
default_from=lambda givenname, sn: givenname[0] + sn,
)
takes_options = ('givenname', 'sn')
cmd = user_add()
cmd.env = config.Env(context='cli')
cmd.finalize()
assert list(cmd.params) == ['givenname', 'sn', 'uid']
ret = cmd.soft_validate({})
assert len(ret['values']) == 0
assert len(ret['errors']) == 3
assert cmd.soft_validate(dict(givenname=u'First', sn=u'Last')) == dict(
values=dict(givenname=u'First', sn=u'Last', uid=u'flast'),
errors=dict(),
)
def test_convert(self):
"""
Test the `ipalib.frontend.Command.convert` method.
"""
kw = dict(
option0=u'1.5',
option1=u'7',
)
o = self.subcls()
o.finalize()
for (key, value) in o.convert(**kw).iteritems():
assert_equal(unicode(kw[key]), value)
def test_normalize(self):
"""
Test the `ipalib.frontend.Command.normalize` method.
"""
kw = dict(
option0=u'OPTION0',
option1=u'OPTION1',
)
norm = dict((k, v.lower()) for (k, v) in kw.items())
sub = self.subcls()
sub.finalize()
assert sub.normalize(**kw) == norm
def test_get_default(self):
"""
Test the `ipalib.frontend.Command.get_default` method.
"""
# FIXME: Add an updated unit tests for get_default()
def test_default_from_chaining(self):
"""
Test chaining of parameters through default_from.
"""
class my_cmd(self.cls):
takes_options = (
Str('option0'),
Str('option1', default_from=lambda option0: option0),
Str('option2', default_from=lambda option1: option1),
)
def run(self, *args, **options):
return dict(result=options)
kw = dict(option0=u'some value')
(api, home) = create_test_api()
api.finalize()
o = my_cmd()
o.set_api(api)
o.finalize()
e = o(**kw)
assert type(e) is dict
assert 'result' in e
assert 'option2' in e['result']
assert e['result']['option2'] == u'some value'
def test_validate(self):
"""
Test the `ipalib.frontend.Command.validate` method.
"""
sub = self.subcls()
sub.env = config.Env(context='cli')
sub.finalize()
# Check with valid values
okay = dict(
option0=u'option0',
option1=u'option1',
another_option='some value',
version=API_VERSION,
)
sub.validate(**okay)
# Check with an invalid value
fail = dict(okay)
fail['option0'] = u'whatever'
e = raises(errors.ValidationError, sub.validate, **fail)
assert_equal(e.name, 'option0')
assert_equal(e.value, u'whatever')
assert_equal(e.error, u"must equal 'option0'")
assert e.rule.__class__.__name__ == 'Rule'
assert e.index is None
# Check with a missing required arg
fail = dict(okay)
fail.pop('option1')
e = raises(errors.RequirementError, sub.validate, **fail)
assert e.name == 'option1'
def test_execute(self):
"""
Test the `ipalib.frontend.Command.execute` method.
"""
o = self.cls()
e = raises(NotImplementedError, o.execute)
assert str(e) == 'Command.execute()'
def test_args_options_2_params(self):
"""
Test the `ipalib.frontend.Command.args_options_2_params` method.
"""
# Test that ZeroArgumentError is raised:
o = self.get_instance()
e = raises(errors.ZeroArgumentError, o.args_options_2_params, 1)
assert e.name == 'example'
# Test that MaxArgumentError is raised (count=1)
o = self.get_instance(args=('one?',))
e = raises(errors.MaxArgumentError, o.args_options_2_params, 1, 2)
assert e.name == 'example'
assert e.count == 1
assert str(e) == "command 'example' takes at most 1 argument"
# Test that MaxArgumentError is raised (count=2)
o = self.get_instance(args=('one', 'two?'))
e = raises(errors.MaxArgumentError, o.args_options_2_params, 1, 2, 3)
assert e.name == 'example'
assert e.count == 2
assert str(e) == "command 'example' takes at most 2 arguments"
# Test that OverlapError is raised:
o = self.get_instance(args=('one', 'two'), options=('three', 'four'))
e = raises(errors.OverlapError, o.args_options_2_params,
1, 2, three=3, two=2, four=4, one=1)
assert e.names == ['one', 'two']
# Test the permutations:
o = self.get_instance(args=('one', 'two*'), options=('three', 'four'))
mthd = o.args_options_2_params
assert mthd() == dict()
assert mthd(1) == dict(one=1)
assert mthd(1, 2) == dict(one=1, two=(2,))
assert mthd(1, 21, 22, 23) == dict(one=1, two=(21, 22, 23))
assert mthd(1, (21, 22, 23)) == dict(one=1, two=(21, 22, 23))
assert mthd(three=3, four=4) == dict(three=3, four=4)
assert mthd(three=3, four=4, one=1, two=2) == \
dict(one=1, two=2, three=3, four=4)
assert mthd(1, 21, 22, 23, three=3, four=4) == \
dict(one=1, two=(21, 22, 23), three=3, four=4)
assert mthd(1, (21, 22, 23), three=3, four=4) == \
dict(one=1, two=(21, 22, 23), three=3, four=4)
def test_args_options_2_entry(self):
"""
Test `ipalib.frontend.Command.args_options_2_entry` method.
"""
class my_cmd(self.cls):
takes_args = (
parameters.Str('one', attribute=True),
parameters.Str('two', attribute=False),
)
takes_options = (
parameters.Str('three', attribute=True, multivalue=True),
parameters.Str('four', attribute=True, multivalue=False),
)
def run(self, *args, **kw):
return self.args_options_2_entry(*args, **kw)
args = ('one', 'two')
kw = dict(three=('three1', 'three2'), four='four')
(api, home) = create_test_api()
api.finalize()
o = my_cmd()
o.set_api(api)
o.finalize()
e = o.run(*args, **kw)
assert type(e) is dict
assert 'one' in e
assert 'two' not in e
assert 'three' in e
assert 'four' in e
assert e['one'] == 'one'
assert e['three'] == ['three1', 'three2']
assert e['four'] == 'four'
def test_params_2_args_options(self):
"""
Test the `ipalib.frontend.Command.params_2_args_options` method.
"""
o = self.get_instance(args='one', options='two')
assert o.params_2_args_options() == ((None,), {})
assert o.params_2_args_options(one=1) == ((1,), {})
assert o.params_2_args_options(two=2) == ((None,), dict(two=2))
assert o.params_2_args_options(two=2, one=1) == ((1,), dict(two=2))
def test_run(self):
"""
Test the `ipalib.frontend.Command.run` method.
"""
class my_cmd(self.cls):
def execute(self, *args, **kw):
return ('execute', args, kw)
def forward(self, *args, **kw):
return ('forward', args, kw)
args = ('Hello,', 'world,')
kw = dict(how_are='you', on_this='fine day?', version=API_VERSION)
# Test in server context:
(api, home) = create_test_api(in_server=True)
api.finalize()
o = my_cmd()
o.set_api(api)
assert o.run.im_func is self.cls.run.im_func
out = o.run(*args, **kw)
del kw['version']
assert ('execute', args, kw) == out
# Test in non-server context
(api, home) = create_test_api(in_server=False)
api.finalize()
o = my_cmd()
o.set_api(api)
assert o.run.im_func is self.cls.run.im_func
assert ('forward', args, kw) == o.run(*args, **kw)
def test_validate_output(self):
"""
Test the `ipalib.frontend.Command.validate_output` method.
"""
class Example(self.cls):
has_output = ('foo', 'bar', 'baz')
inst = Example()
inst.finalize()
# Test with wrong type:
wrong = ('foo', 'bar', 'baz')
e = raises(TypeError, inst.validate_output, wrong)
assert str(e) == '%s.validate_output(): need a %r; got a %r: %r' % (
'Example', dict, tuple, wrong
)
# Test with a missing keys:
wrong = dict(bar='hello')
e = raises(ValueError, inst.validate_output, wrong)
assert str(e) == '%s.validate_output(): missing keys %r in %r' % (
'Example', ['baz', 'foo'], wrong
)
# Test with extra keys:
wrong = dict(foo=1, bar=2, baz=3, fee=4, azz=5)
e = raises(ValueError, inst.validate_output, wrong)
assert str(e) == '%s.validate_output(): unexpected keys %r in %r' % (
'Example', ['azz', 'fee'], wrong
)
# Test with per item type validation:
class Complex(self.cls):
has_output = (
output.Output('foo', int),
output.Output('bar', list),
)
inst = Complex()
inst.finalize()
wrong = dict(foo=17.9, bar=[18])
e = raises(TypeError, inst.validate_output, wrong)
assert str(e) == '%s:\n output[%r]: need %r; got %r: %r' % (
'Complex.validate_output()', 'foo', int, float, 17.9
)
wrong = dict(foo=18, bar=17)
e = raises(TypeError, inst.validate_output, wrong)
assert str(e) == '%s:\n output[%r]: need %r; got %r: %r' % (
'Complex.validate_output()', 'bar', list, int, 17
)
class Subclass(output.ListOfEntries):
pass
# Test nested validation:
class nested(self.cls):
has_output = (
output.Output('hello', int),
Subclass('world'),
)
inst = nested()
inst.finalize()
okay = dict(foo='bar')
nope = ('aye', 'bee')
wrong = dict(hello=18, world=[okay, nope, okay])
e = raises(TypeError, inst.validate_output, wrong)
assert str(e) == output.emsg % (
'nested', 'Subclass', 'world', 1, dict, tuple, nope
)
wrong = dict(hello=18, world=[okay, okay, okay, okay, nope])
e = raises(TypeError, inst.validate_output, wrong)
assert str(e) == output.emsg % (
'nested', 'Subclass', 'world', 4, dict, tuple, nope
)
def test_get_output_params(self):
"""
Test the `ipalib.frontend.Command.get_output_params` method.
"""
class example(self.cls):
has_output_params = (
'one',
'two',
'three',
)
takes_args = (
'foo',
)
takes_options = (
Str('bar', flags='no_output'),
'baz',
)
inst = example()
assert list(inst.get_output_params()) == ['one', 'two', 'three']
inst.finalize()
assert list(inst.get_output_params()) == [
'one', 'two', 'three', inst.params.foo, inst.params.baz
]
assert list(inst.output_params) == ['one', 'two', 'three', 'foo', 'baz']
class test_LocalOrRemote(ClassChecker):
"""
Test the `ipalib.frontend.LocalOrRemote` class.
"""
_cls = frontend.LocalOrRemote
def test_init(self):
"""
Test the `ipalib.frontend.LocalOrRemote.__init__` method.
"""
o = self.cls()
o.finalize()
assert list(o.args) == []
assert list(o.options) == ['server']
op = o.options.server
assert op.required is False
assert op.default is False
def test_run(self):
"""
Test the `ipalib.frontend.LocalOrRemote.run` method.
"""
class example(self.cls):
takes_args = 'key?'
def forward(self, *args, **options):
return dict(result=('forward', args, options))
def execute(self, *args, **options):
return dict(result=('execute', args, options))
# Test when in_server=False:
(api, home) = create_test_api(in_server=False)
api.register(example)
api.finalize()
cmd = api.Command.example
assert cmd() == dict(
result=('execute', (None,), dict(server=False))
)
assert cmd(u'var') == dict(
result=('execute', (u'var',), dict(server=False))
)
assert cmd(server=True) == dict(
result=('forward', (None,), dict(server=True))
)
assert cmd(u'var', server=True) == dict(
result=('forward', (u'var',), dict(server=True))
)
# Test when in_server=True (should always call execute):
(api, home) = create_test_api(in_server=True)
api.register(example)
api.finalize()
cmd = api.Command.example
assert cmd() == dict(
result=('execute', (None,), dict(server=False))
)
assert cmd(u'var') == dict(
result=('execute', (u'var',), dict(server=False))
)
assert cmd(server=True) == dict(
result=('execute', (None,), dict(server=True))
)
assert cmd(u'var', server=True) == dict(
result=('execute', (u'var',), dict(server=True))
)
class test_Object(ClassChecker):
"""
Test the `ipalib.frontend.Object` class.
"""
_cls = frontend.Object
def test_class(self):
"""
Test the `ipalib.frontend.Object` class.
"""
assert self.cls.backend is None
assert self.cls.methods is None
assert self.cls.properties is None
assert self.cls.params is None
assert self.cls.params_minus_pk is None
assert self.cls.takes_params == tuple()
def test_init(self):
"""
Test the `ipalib.frontend.Object.__init__` method.
"""
o = self.cls()
assert o.backend is None
assert o.methods is None
assert o.properties is None
assert o.params is None
assert o.params_minus_pk is None
assert o.properties is None
def test_set_api(self):
"""
Test the `ipalib.frontend.Object.set_api` method.
"""
# Setup for test:
class DummyAttribute(object):
def __init__(self, obj_name, attr_name, name=None):
self.obj_name = obj_name
self.attr_name = attr_name
if name is None:
self.name = '%s_%s' % (obj_name, attr_name)
else:
self.name = name
self.param = frontend.create_param(attr_name)
def __clone__(self, attr_name):
return self.__class__(
self.obj_name,
self.attr_name,
getattr(self, attr_name)
)
def get_attributes(cnt, format):
for name in ['other', 'user', 'another']:
for i in xrange(cnt):
yield DummyAttribute(name, format % i)
cnt = 10
formats = dict(
methods='method_%d',
properties='property_%d',
)
_d = dict(
Method=plugable.NameSpace(
get_attributes(cnt, formats['methods'])
),
Property=plugable.NameSpace(
get_attributes(cnt, formats['properties'])
),
)
api = plugable.MagicDict(_d)
assert len(api.Method) == cnt * 3
assert len(api.Property) == cnt * 3
class user(self.cls):
pass
# Actually perform test:
o = user()
o.set_api(api)
assert read_only(o, 'api') is api
for name in ['methods', 'properties']:
namespace = getattr(o, name)
assert isinstance(namespace, plugable.NameSpace)
assert len(namespace) == cnt
f = formats[name]
for i in xrange(cnt):
attr_name = f % i
attr = namespace[attr_name]
assert isinstance(attr, DummyAttribute)
assert attr is getattr(namespace, attr_name)
assert attr.obj_name == 'user'
assert attr.attr_name == attr_name
assert attr.name == '%s_%s' % ('user', attr_name)
# Test params instance attribute
o = self.cls()
o.set_api(api)
ns = o.params
assert type(ns) is plugable.NameSpace
assert len(ns) == 0
class example(self.cls):
takes_params = ('banana', 'apple')
o = example()
o.set_api(api)
ns = o.params
assert type(ns) is plugable.NameSpace
assert len(ns) == 2, repr(ns)
assert list(ns) == ['banana', 'apple']
for p in ns():
assert type(p) is parameters.Str
assert p.required is True
assert p.multivalue is False
def test_primary_key(self):
"""
Test the `ipalib.frontend.Object.primary_key` attribute.
"""
(api, home) = create_test_api()
api.finalize()
# Test with no primary keys:
class example1(self.cls):
takes_params = (
'one',
'two',
)
o = example1()
o.set_api(api)
assert o.primary_key is None
# Test with 1 primary key:
class example2(self.cls):
takes_params = (
'one',
'two',
parameters.Str('three', primary_key=True),
'four',
)
o = example2()
o.set_api(api)
pk = o.primary_key
assert type(pk) is parameters.Str
assert pk.name == 'three'
assert pk.primary_key is True
assert o.params[2] is o.primary_key
assert isinstance(o.params_minus_pk, plugable.NameSpace)
assert list(o.params_minus_pk) == ['one', 'two', 'four']
# Test with multiple primary_key:
class example3(self.cls):
takes_params = (
parameters.Str('one', primary_key=True),
parameters.Str('two', primary_key=True),
'three',
parameters.Str('four', primary_key=True),
)
o = example3()
o.set_api(api)
e = raises(ValueError, o.finalize)
assert str(e) == \
'example3 (Object) has multiple primary keys: one, two, four'
def test_backend(self):
"""
Test the `ipalib.frontend.Object.backend` attribute.
"""
(api, home) = create_test_api()
class ldap(backend.Backend):
whatever = 'It worked!'
api.register(ldap)
class user(frontend.Object):
backend_name = 'ldap'
api.register(user)
api.finalize()
b = api.Object.user.backend
assert isinstance(b, ldap)
assert b.whatever == 'It worked!'
def test_get_dn(self):
"""
Test the `ipalib.frontend.Object.get_dn` method.
"""
o = self.cls()
e = raises(NotImplementedError, o.get_dn, 'primary key')
assert str(e) == 'Object.get_dn()'
class user(self.cls):
pass
o = user()
e = raises(NotImplementedError, o.get_dn, 'primary key')
assert str(e) == 'user.get_dn()'
def test_params_minus(self):
"""
Test the `ipalib.frontend.Object.params_minus` method.
"""
class example(self.cls):
takes_params = ('one', 'two', 'three', 'four')
o = example()
(api, home) = create_test_api()
o.set_api(api)
p = o.params
assert tuple(o.params_minus()) == tuple(p())
assert tuple(o.params_minus([])) == tuple(p())
assert tuple(o.params_minus('two', 'three')) == (p.one, p.four)
assert tuple(o.params_minus(['two', 'three'])) == (p.one, p.four)
assert tuple(o.params_minus(p.two, p.three)) == (p.one, p.four)
assert tuple(o.params_minus([p.two, p.three])) == (p.one, p.four)
ns = NameSpace([p.two, p.three])
assert tuple(o.params_minus(ns)) == (p.one, p.four)
class test_Attribute(ClassChecker):
"""
Test the `ipalib.frontend.Attribute` class.
"""
_cls = frontend.Attribute
def test_class(self):
"""
Test the `ipalib.frontend.Attribute` class.
"""
assert self.cls.__bases__ == (plugable.Plugin,)
assert type(self.cls.obj) is property
assert type(self.cls.obj_name) is property
assert type(self.cls.attr_name) is property
def test_init(self):
"""
Test the `ipalib.frontend.Attribute.__init__` method.
"""
class user_add(self.cls):
pass
o = user_add()
assert read_only(o, 'obj') is None
assert read_only(o, 'obj_name') == 'user'
assert read_only(o, 'attr_name') == 'add'
def test_set_api(self):
"""
Test the `ipalib.frontend.Attribute.set_api` method.
"""
user_obj = 'The user frontend.Object instance'
class api(object):
Object = dict(user=user_obj)
class user_add(self.cls):
pass
o = user_add()
assert read_only(o, 'api') is None
assert read_only(o, 'obj') is None
o.set_api(api)
assert read_only(o, 'api') is api
assert read_only(o, 'obj') is user_obj
class test_Method(ClassChecker):
"""
Test the `ipalib.frontend.Method` class.
"""
_cls = frontend.Method
def get_api(self, args=tuple(), options=tuple()):
"""
Return a finalized `ipalib.plugable.API` instance.
"""
(api, home) = create_test_api()
class user(frontend.Object):
takes_params = (
'givenname',
'sn',
frontend.Param('uid', primary_key=True),
'initials',
)
class user_verb(self.cls):
takes_args = args
takes_options = options
api.register(user)
api.register(user_verb)
api.finalize()
return api
def test_class(self):
"""
Test the `ipalib.frontend.Method` class.
"""
assert self.cls.__bases__ == (frontend.Attribute, frontend.Command)
def test_init(self):
"""
Test the `ipalib.frontend.Method.__init__` method.
"""
class user_add(self.cls):
pass
o = user_add()
assert o.name == 'user_add'
assert o.obj_name == 'user'
assert o.attr_name == 'add'
class test_Property(ClassChecker):
"""
Test the `ipalib.frontend.Property` class.
"""
_cls = frontend.Property
def get_subcls(self):
"""
Return a standard subclass of `ipalib.frontend.Property`.
"""
class user_givenname(self.cls):
'User first name'
@frontend.rule
def rule0_lowercase(self, value):
if not value.islower():
return 'Must be lowercase'
return user_givenname
def test_class(self):
"""
Test the `ipalib.frontend.Property` class.
"""
assert self.cls.__bases__ == (frontend.Attribute,)
assert self.cls.klass is parameters.Str
def test_init(self):
"""
Test the `ipalib.frontend.Property.__init__` method.
"""
o = self.subcls()
assert len(o.rules) == 1
assert o.rules[0].__name__ == 'rule0_lowercase'
param = o.param
assert isinstance(param, parameters.Str)
assert param.name == 'givenname'
assert unicode(param.doc) == u'User first name'