# Authors: # Jason Gerard DeRose # # 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 . """ Test the `ipalib.frontend` module. """ import pytest import six from ipatests.util import raises, read_only from ipatests.util import ClassChecker, create_test_api from ipatests.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, messages from ipalib.parameters import Str from ipapython.version import API_VERSION if six.PY3: unicode = str pytestmark = pytest.mark.tier0 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: 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. """ api = 'the api instance' class WithTuple(self.cls): takes_stuff = ('one', 'two') o = WithTuple(api) 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(api) assert o._get_param_iterable('stuff') is junk class WithParam(self.cls): takes_stuff = parameters.Str('five') o = WithParam(api) assert o._get_param_iterable('stuff') == (WithParam.takes_stuff,) class WithStr(self.cls): takes_stuff = 'six' o = WithStr(api) assert o._get_param_iterable('stuff') == ('six',) class Wrong(self.cls): takes_stuff = ['seven', 'eight'] o = Wrong(api) 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. """ api = 'the api instance' 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(api) # 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(api) 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(api) 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: def __init__(self, name): self.name = name def __call__(self, _, value): if value != self.name: return _('must equal %r') % self.name else: return None default_from = parameters.DefaultFrom( lambda arg: arg, 'default_from' ) def normalizer(value): return 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 api: @staticmethod def is_production_mode(): return False class example(self.cls): takes_args = args takes_options = options o = example(api) 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. """ api = 'the api instance' assert list(self.cls(api).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. """ api = 'the api instance' options = list(self.cls(api).get_options()) assert len(options) == 1 assert options[0].name == 'version' options = ('verbose', 'debug') o = self.get_instance(options=options) assert len(tuple(o.get_options())) == 3 assert 'verbose' in tuple(o.get_options()) assert 'debug' in tuple(o.get_options()) def test_args(self): """ Test the ``ipalib.frontend.Command.args`` instance attribute. """ class api: @staticmethod def is_production_mode(): return False o = self.cls(api) o.finalize() assert type(o.args) is NameSpace assert len(o.args) == 0 args = ('destination', 'source?') ns = self.get_instance(args=args).args assert type(ns) is 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: if six.PY2: e = raises(TypeError, self.get_instance, args=(u'whatever',)) assert str(e) == TYPE_ERROR % ( 'spec', (str, parameters.Param), u'whatever', unicode) else: e = raises(TypeError, self.get_instance, args=(b'whatever',)) assert str(e) == TYPE_ERROR % ( 'spec', (str, parameters.Param), b'whatever', bytes) # Test ValueError, required after optional: e = raises(ValueError, self.get_instance, args=('arg1?', 'arg2')) assert str(e) == "arg2: required argument after optional in %s arguments ['arg1?', 'arg2']" % (self.get_instance().name) # 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. """ class api: @staticmethod def is_production_mode(): return False o = self.cls(api) o.finalize() assert type(o.options) is NameSpace assert len(o.options) == 1 options = ('target', 'files*') ns = self.get_instance(options=options).options assert type(ns) is NameSpace assert len(ns) == len(options) + 1 assert list(ns) == ['target', 'files', 'version'] 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. """ class api: @staticmethod def is_production_mode(): return False inst = self.cls(api) inst.finalize() assert type(inst.output) is NameSpace assert list(inst.output) == ['result'] # pylint: disable=no-member assert type(inst.output.result) is output.Output # pylint: enable=no-member def test_iter_output(self): """ Test the ``ipalib.frontend.Command._iter_output`` instance attribute. """ api = 'the api instance' class Example(self.cls): pass inst = Example(api) 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_convert(self): """ Test the `ipalib.frontend.Command.convert` method. """ class api: @staticmethod def is_production_mode(): return False kw = dict( option0=u'1.5', option1=u'7', ) o = self.subcls(api) o.finalize() for (key, value) in o.convert(**kw).items(): assert_equal(unicode(kw[key]), value) def test_normalize(self): """ Test the `ipalib.frontend.Command.normalize` method. """ class api: @staticmethod def is_production_mode(): return False kw = dict( option0=u'OPTION0', option1=u'OPTION1', ) norm = dict((k, v.lower()) for (k, v) in kw.items()) sub = self.subcls(api) 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(api) o.finalize() e = o.get_default(**kw) assert type(e) is dict assert 'option2' in e assert e['option2'] == u'some value' def test_validate(self): """ Test the `ipalib.frontend.Command.validate` method. """ class api: env = config.Env(context='cli') @staticmethod def is_production_mode(): return False sub = self.subcls(api) 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, u'option0') assert_equal(e.error, u"must equal 'option0'") # 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. """ api = 'the api instance' o = self.cls(api) 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 OptionError is raised when an extra option is given: o = self.get_instance() e = raises(errors.OptionError, o.args_options_2_params, bad_option=True) assert e.option == 'bad_option' # 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(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() == ((), {}) assert o.params_2_args_options(one=1) == ((1,), {}) assert o.params_2_args_options(two=2) == ((), 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(api) if six.PY2: assert o.run.__func__ is self.cls.run.__func__ else: assert o.run.__func__ is self.cls.run out = o.run(*args, **kw) assert ('execute', args, kw) == out # Test in non-server context api, _home = create_test_api(in_server=False) api.finalize() o = my_cmd(api) if six.PY2: assert o.run.__func__ is self.cls.run.__func__ else: assert o.run.__func__ is self.cls.run assert ('forward', args, kw) == o.run(*args, **kw) def test_messages(self): """ Test correct handling of messages """ class TestMessage(messages.PublicMessage): type = 'info' format = 'This is a message.' errno = 1234 class my_cmd(self.cls): def execute(self, *args, **kw): result = {'name': 'execute'} messages.add_message(kw['version'], result, TestMessage()) return result def forward(self, *args, **kw): result = {'name': 'forward'} messages.add_message(kw['version'], result, TestMessage()) return result args = ('Hello,', 'world,') kw = dict(how_are='you', on_this='fine day?', version=API_VERSION) expected = [TestMessage().to_dict()] # Test in server context: api, _home = create_test_api(in_server=True) api.finalize() o = my_cmd(api) if six.PY2: assert o.run.__func__ is self.cls.run.__func__ else: assert o.run.__func__ is self.cls.run assert {'name': 'execute', 'messages': expected} == o.run(*args, **kw) # Test in non-server context api, _home = create_test_api(in_server=False) api.finalize() o = my_cmd(api) if six.PY2: assert o.run.__func__ is self.cls.run.__func__ else: assert o.run.__func__ is self.cls.run assert {'name': 'forward', 'messages': expected} == o.run(*args, **kw) def test_validate_output_basic(self): """ Test the `ipalib.frontend.Command.validate_output` method. """ class api: @staticmethod def is_production_mode(): return False class Example(self.cls): has_output = ('foo', 'bar', 'baz') inst = Example(api) 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 different keys: wrong = dict(baz=1, xyzzy=2, quux=3) e = raises(ValueError, inst.validate_output, wrong) assert str(e) == '%s.validate_output(): missing keys %r in %r' % ( 'Example', ['bar', 'foo'], wrong ), str(e) def test_validate_output_per_type(self): """ Test `ipalib.frontend.Command.validate_output` per-type validation. """ class api: @staticmethod def is_production_mode(): return False class Complex(self.cls): has_output = ( output.Output('foo', int), output.Output('bar', list), ) inst = Complex(api) 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 ) def test_validate_output_nested(self): """ Test `ipalib.frontend.Command.validate_output` nested validation. """ class api: @staticmethod def is_production_mode(): return False class Subclass(output.ListOfEntries): pass # Test nested validation: class nested(self.cls): has_output = ( output.Output('hello', int), Subclass('world'), ) inst = nested(api) 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 api: @staticmethod def is_production_mode(): return False class example(self.cls): has_output_params = ( 'one', 'two', 'three', ) takes_args = ( 'foo', ) takes_options = ( Str('bar'), 'baz', ) inst = example(api) inst.finalize() assert list(inst.get_output_params()) == [ 'one', 'two', 'three' ] assert list(inst.output_params) == ['one', 'two', 'three'] class test_LocalOrRemote(ClassChecker): """ Test the `ipalib.frontend.LocalOrRemote` class. """ _cls = frontend.LocalOrRemote def test_init(self): """ Test the `ipalib.frontend.LocalOrRemote.__init__` method. """ class api: @staticmethod def is_production_mode(): return False o = self.cls(api) o.finalize() assert list(o.args) == [] assert list(o.options) == ['server', 'version'] 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.add_plugin(example) api.finalize() cmd = api.Command.example assert cmd(version=u'2.47') == dict( result=('execute', (), dict(version=u'2.47')) ) assert cmd(u'var', version=u'2.47') == dict( result=('execute', (u'var',), dict(version=u'2.47')) ) assert cmd(server=True, version=u'2.47') == dict( result=('forward', (), dict(version=u'2.47', server=True)) ) assert cmd(u'var', server=True, version=u'2.47') == dict( result=('forward', (u'var',), dict(version=u'2.47', server=True)) ) # Test when in_server=True (should always call execute): api, _home = create_test_api(in_server=True) api.add_plugin(example) api.finalize() cmd = api.Command.example assert cmd(version=u'2.47') == dict( result=('execute', (), dict(version=u'2.47', server=False)) ) assert cmd(u'var', version=u'2.47') == dict( result=('execute', (u'var',), dict(version=u'2.47', server=False)) ) assert cmd(server=True, version=u'2.47') == dict( result=('execute', (), dict(version=u'2.47', server=True)) ) assert cmd(u'var', server=True, version=u'2.47') == dict( result=('execute', (u'var',), dict(version=u'2.47', 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.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. """ # Setup for test: class DummyAttribute: 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.bases = (DummyAttribute,) self.version = '1' self.full_name = '{}/{}'.format(self.name, self.version) 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 range(cnt): yield DummyAttribute(name, format % i) cnt = 10 methods_format = 'method_%d' class FakeAPI: def __init__(self): self._API__plugins = get_attributes(cnt, methods_format) self._API__default_map = {} self.Method = plugable.APINameSpace(self, DummyAttribute) def __contains__(self, key): return hasattr(self, key) def __getitem__(self, key): return getattr(self, key) def is_production_mode(self): return False def _get(self, plugin): return plugin api = FakeAPI() assert len(api.Method) == cnt * 3 class user(self.cls): pass # Actually perform test: o = user(api) assert read_only(o, 'api') is api namespace = o.methods assert isinstance(namespace, NameSpace) assert len(namespace) == cnt f = methods_format for i in range(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(api) ns = o.params assert type(ns) is NameSpace assert len(ns) == 0 class example(self.cls): takes_params = ('banana', 'apple') o = example(api) ns = o.params assert type(ns) is 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(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(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, 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(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.add_plugin(ldap) class user(frontend.Object): backend_name = 'ldap' api.add_plugin(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. """ api = 'the api instance' o = self.cls(api) e = raises(NotImplementedError, o.get_dn, 'primary key') assert str(e) == 'Object.get_dn()' class user(self.cls): pass o = user(api) 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') api, _home = create_test_api() api.finalize() o = example(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. """ user_obj = 'The user frontend.Object instance' class api: Object = {("user", "1"): user_obj} @staticmethod def is_production_mode(): return False class user_add(self.cls): pass o = user_add(api) assert read_only(o, 'api') is api assert read_only(o, 'obj') is user_obj assert read_only(o, 'obj_name') == 'user' assert read_only(o, 'attr_name') == 'add' 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.add_plugin(user) api.add_plugin(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. """ api = 'the api instance' class user_add(self.cls): pass o = user_add(api) assert o.name == 'user_add' assert o.obj_name == 'user' assert o.attr_name == 'add'