mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-23 07:33:27 -06:00
9: Reorganized new work and unit tests based around base.Object being the plugin definining unit
This commit is contained in:
parent
e76160b01d
commit
ccd8eb3373
113
ipalib/base.py
113
ipalib/base.py
@ -25,51 +25,6 @@ import inspect
|
||||
import exceptions
|
||||
|
||||
|
||||
class Named(object):
|
||||
prefix = None
|
||||
|
||||
def __init__(self):
|
||||
clsname = self.__class__.__name__
|
||||
assert type(self.prefix) is str
|
||||
prefix = self.prefix + '_'
|
||||
if not clsname.startswith(prefix):
|
||||
raise exceptions.PrefixError(clsname, prefix)
|
||||
self.__name = clsname[len(prefix):]
|
||||
self.__name_cli = self.__name.replace('_', '-')
|
||||
|
||||
def __get_name(self):
|
||||
return self.__name
|
||||
name = property(__get_name)
|
||||
|
||||
def __get_name_cli(self):
|
||||
return self.__name_cli
|
||||
name_cli = property(__get_name_cli)
|
||||
|
||||
|
||||
class Command(Named):
|
||||
prefix = 'cmd'
|
||||
|
||||
def normalize(self, kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def validate(self, kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def execute(self, kw):
|
||||
raise NotImplementedError
|
||||
|
||||
def __call__(self, **kw):
|
||||
normalized = self.normalize(kw)
|
||||
invalid = self.validate(normalized)
|
||||
if invalid:
|
||||
return invalid
|
||||
return self.execute(normalize)
|
||||
|
||||
|
||||
class Argument(object):
|
||||
pass
|
||||
|
||||
|
||||
class NameSpace(object):
|
||||
"""
|
||||
A read-only namespace of (key, value) pairs that can be accessed
|
||||
@ -103,8 +58,10 @@ class NameSpace(object):
|
||||
|
||||
def __init__(self, kw, order=None):
|
||||
"""
|
||||
The single constructor argument `kw` is a dict of the (key, value)
|
||||
pairs to be in this NameSpace instance.
|
||||
The `kw` argument is a dict of the (key, value) pairs to be in this
|
||||
NameSpace instance. The optional `order` keyword argument specifies
|
||||
the order of the keys in this namespace; if omitted, the default is
|
||||
to sort the keys in ascending order.
|
||||
"""
|
||||
assert isinstance(kw, dict)
|
||||
self.__kw = dict(kw)
|
||||
@ -141,7 +98,8 @@ class NameSpace(object):
|
||||
|
||||
def __iter__(self):
|
||||
"""
|
||||
Yields the names in this NameSpace in ascending order.
|
||||
Yields the names in this NameSpace in ascending order, or in the
|
||||
the order specified in `order` kw arg.
|
||||
|
||||
For example:
|
||||
|
||||
@ -161,6 +119,65 @@ class NameSpace(object):
|
||||
return len(self.__keys)
|
||||
|
||||
|
||||
class Named(object):
|
||||
def __get_name(self):
|
||||
return self.__class__.__name__
|
||||
name = property(__get_name)
|
||||
|
||||
|
||||
class ObjectMember(Named):
|
||||
def __init__(self, obj):
|
||||
self.__obj = obj
|
||||
|
||||
def __get_obj(self):
|
||||
return self.__obj
|
||||
obj = property(__get_obj)
|
||||
|
||||
|
||||
class Command(ObjectMember):
|
||||
def __get_full_name(self):
|
||||
return '%s_%s' % (self.name, self.obj.name)
|
||||
full_name = property(__get_full_name)
|
||||
|
||||
|
||||
class Attribute(ObjectMember):
|
||||
def __get_full_name(self):
|
||||
return '%s_%s' % (self.obj.name, self.name)
|
||||
full_name = property(__get_full_name)
|
||||
|
||||
|
||||
class Object(Named):
|
||||
def __init__(self):
|
||||
self.__commands = self.__build_ns(self.get_commands)
|
||||
self.__attributes = self.__build_ns(self.get_attributes, True)
|
||||
|
||||
def __get_commands(self):
|
||||
return self.__commands
|
||||
commands = property(__get_commands)
|
||||
|
||||
def __get_attributes(self):
|
||||
return self.__attributes
|
||||
attributes = property(__get_attributes)
|
||||
|
||||
def __build_ns(self, callback, preserve=False):
|
||||
d = {}
|
||||
o = []
|
||||
for cls in callback():
|
||||
i = cls(self)
|
||||
assert i.name not in d
|
||||
d[i.name] = i
|
||||
o.append(i.name)
|
||||
if preserve:
|
||||
return NameSpace(d, order=o)
|
||||
return NameSpace(d)
|
||||
|
||||
def get_commands(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def get_attributes(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class API(object):
|
||||
__cmd = None
|
||||
__objects = None
|
||||
|
@ -18,66 +18,43 @@
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
"""
|
||||
|
||||
Base classes for objects with CRUD functionality.
|
||||
"""
|
||||
|
||||
from base import NameSpace
|
||||
import base
|
||||
|
||||
class Named(object):
|
||||
def __get_name(self):
|
||||
return self.__class__.__name__
|
||||
name = property(__get_name)
|
||||
|
||||
class ObjectMember(Named):
|
||||
def __init__(self, obj):
|
||||
self.__obj = obj
|
||||
|
||||
def __get_obj(self):
|
||||
return self.__obj
|
||||
obj = property(__get_obj)
|
||||
class create(base.Command):
|
||||
pass
|
||||
|
||||
|
||||
class Command(ObjectMember):
|
||||
def __get_full_name(self):
|
||||
return '%s_%s' % (self.name, self.obj.name)
|
||||
full_name = property(__get_full_name)
|
||||
|
||||
class Attribute(ObjectMember):
|
||||
def __get_full_name(self):
|
||||
return '%s_%s' % (self.obj.name, self.name)
|
||||
full_name = property(__get_full_name)
|
||||
class retrieve(base.Command):
|
||||
pass
|
||||
|
||||
|
||||
class Object(Named):
|
||||
def __init__(self):
|
||||
self.__commands = self.__build_ns(self.get_commands)
|
||||
self.__attributes = self.__build_ns(self.get_attributes, True)
|
||||
class update(base.Command):
|
||||
pass
|
||||
|
||||
def __get_commands(self):
|
||||
return self.__commands
|
||||
commands = property(__get_commands)
|
||||
|
||||
def __get_attributes(self):
|
||||
return self.__attributes
|
||||
attributes = property(__get_attributes)
|
||||
class delete(base.Command):
|
||||
pass
|
||||
|
||||
def __build_ns(self, callback, preserve=False):
|
||||
d = {}
|
||||
o = []
|
||||
for cls in callback():
|
||||
i = cls(self)
|
||||
assert i.name not in d
|
||||
d[i.name] = i
|
||||
o.append(i.name)
|
||||
if preserve:
|
||||
return NameSpace(d, order=o)
|
||||
return NameSpace(d)
|
||||
|
||||
def __get_commands(self):
|
||||
return
|
||||
class search(base.Command):
|
||||
pass
|
||||
|
||||
|
||||
class user(base.Object):
|
||||
def get_commands(self):
|
||||
raise NotImplementedError
|
||||
return [
|
||||
create,
|
||||
retrieve,
|
||||
update,
|
||||
delete,
|
||||
]
|
||||
|
||||
def get_attributes(self):
|
||||
raise NotImplementedError
|
||||
return [
|
||||
givenName,
|
||||
sn,
|
||||
login,
|
||||
]
|
||||
|
@ -56,61 +56,6 @@ class ClassChecker(object):
|
||||
return self.new(*self.args(), **self.kw())
|
||||
|
||||
|
||||
class test_Named:
|
||||
"""
|
||||
Unit tests for `Named` class.
|
||||
"""
|
||||
cls = base.Named
|
||||
|
||||
def new(self):
|
||||
class tst_verb_object(self.cls):
|
||||
prefix = 'tst'
|
||||
return tst_verb_object()
|
||||
|
||||
def test_prefix(self):
|
||||
"""
|
||||
Test prefix exception.
|
||||
"""
|
||||
# Test Example class:
|
||||
class Example(self.cls):
|
||||
prefix = 'eg'
|
||||
|
||||
# Two test subclasses:
|
||||
class do_stuff(Example):
|
||||
pass
|
||||
class eg_do_stuff(Example):
|
||||
pass
|
||||
|
||||
# Test that PrefixError is raised with incorrectly named subclass:
|
||||
raised = False
|
||||
try:
|
||||
do_stuff()
|
||||
except exceptions.PrefixError:
|
||||
raised = True
|
||||
assert raised
|
||||
|
||||
# Test that correctly named subclass works:
|
||||
eg_do_stuff()
|
||||
|
||||
def test_name(self):
|
||||
"""
|
||||
Test Named.name property.
|
||||
"""
|
||||
obj = self.new()
|
||||
assert read_only(obj, 'name') == 'verb_object'
|
||||
|
||||
def test_name_cli(self):
|
||||
"""
|
||||
Test Named.name_cli property.
|
||||
"""
|
||||
obj = self.new()
|
||||
assert read_only(obj, 'name_cli') == 'verb-object'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class test_NameSpace:
|
||||
"""
|
||||
Unit tests for `NameSpace` class.
|
||||
@ -238,17 +183,93 @@ class test_NameSpace:
|
||||
assert len(kw) == len(ns) == 3
|
||||
|
||||
|
||||
class test_Command(ClassChecker):
|
||||
class cmd_some_command(base.Command):
|
||||
def test_Command():
|
||||
class user(object):
|
||||
name = 'user'
|
||||
class add(base.Command):
|
||||
pass
|
||||
cls = cmd_some_command
|
||||
i = add(user())
|
||||
assert i.name == 'add'
|
||||
assert i.full_name == 'add_user'
|
||||
|
||||
def test_fresh(self):
|
||||
c = self.new()
|
||||
assert isinstance(c, base.Named)
|
||||
assert c.name == 'some_command'
|
||||
assert c.name_cli == 'some-command'
|
||||
assert callable(c)
|
||||
|
||||
def test_Attribute():
|
||||
class user(object):
|
||||
name = 'user'
|
||||
class sn(base.Attribute):
|
||||
pass
|
||||
i = sn(user())
|
||||
assert i.name == 'sn'
|
||||
assert i.full_name == 'user_sn'
|
||||
|
||||
|
||||
def test_Object():
|
||||
class create(base.Command):
|
||||
pass
|
||||
|
||||
class retrieve(base.Command):
|
||||
pass
|
||||
|
||||
class update(base.Command):
|
||||
pass
|
||||
|
||||
class delete(base.Command):
|
||||
pass
|
||||
|
||||
class givenName(base.Attribute):
|
||||
pass
|
||||
|
||||
class sn(base.Attribute):
|
||||
pass
|
||||
|
||||
class login(base.Attribute):
|
||||
pass
|
||||
|
||||
|
||||
class user(base.Object):
|
||||
def get_commands(self):
|
||||
return [
|
||||
create,
|
||||
retrieve,
|
||||
update,
|
||||
delete,
|
||||
]
|
||||
|
||||
def get_attributes(self):
|
||||
return [
|
||||
givenName,
|
||||
sn,
|
||||
login,
|
||||
]
|
||||
|
||||
i = user()
|
||||
assert i.name == 'user'
|
||||
|
||||
# Test commands:
|
||||
commands = i.commands
|
||||
assert isinstance(commands, base.NameSpace)
|
||||
assert list(commands) == ['create', 'delete', 'retrieve', 'update']
|
||||
assert len(commands) == 4
|
||||
for name in commands:
|
||||
cls = locals()[name]
|
||||
cmd = commands[name]
|
||||
assert type(cmd) is cls
|
||||
assert getattr(commands, name) is cmd
|
||||
assert cmd.name == name
|
||||
assert cmd.full_name == ('%s_user' % name)
|
||||
|
||||
# Test attributes:
|
||||
attributes = i.attributes
|
||||
assert isinstance(attributes, base.NameSpace)
|
||||
assert list(attributes) == ['givenName', 'sn', 'login']
|
||||
assert len(attributes) == 3
|
||||
for name in attributes:
|
||||
cls = locals()[name]
|
||||
attr = attributes[name]
|
||||
assert type(attr) is cls
|
||||
assert getattr(attributes, name) is attr
|
||||
assert attr.name == name
|
||||
assert attr.full_name == ('user_%s' % name)
|
||||
|
||||
|
||||
class test_API:
|
||||
@ -262,14 +283,14 @@ class test_API:
|
||||
"""
|
||||
return base.API()
|
||||
|
||||
def test_fresh(self):
|
||||
def dont_fresh(self):
|
||||
"""
|
||||
Test expectations of a fresh API instance.
|
||||
"""
|
||||
api = self.new()
|
||||
assert read_only(api, 'cmd') is None
|
||||
|
||||
def test_register_command(self):
|
||||
def dont_register_command(self):
|
||||
api = self.new()
|
||||
|
||||
class cmd_my_command(base.Command):
|
||||
@ -314,7 +335,7 @@ class test_API:
|
||||
# Check that override=True works:
|
||||
api.register_command(cmd_my_command, override=True)
|
||||
|
||||
def test_finalize(self):
|
||||
def dont_finalize(self):
|
||||
api = self.new()
|
||||
assert read_only(api, 'cmd') is None
|
||||
|
||||
|
@ -20,92 +20,3 @@
|
||||
"""
|
||||
Unit tests for `ipalib.crud` module.
|
||||
"""
|
||||
|
||||
from ipalib import crud, base, exceptions
|
||||
|
||||
class create(crud.Command):
|
||||
pass
|
||||
|
||||
class retrieve(crud.Command):
|
||||
pass
|
||||
|
||||
class update(crud.Command):
|
||||
pass
|
||||
|
||||
class delete(crud.Command):
|
||||
pass
|
||||
|
||||
class givenName(crud.Attribute):
|
||||
pass
|
||||
|
||||
class sn(crud.Attribute):
|
||||
pass
|
||||
|
||||
class login(crud.Attribute):
|
||||
pass
|
||||
|
||||
|
||||
class user(crud.Object):
|
||||
def get_commands(self):
|
||||
return [
|
||||
create,
|
||||
retrieve,
|
||||
update,
|
||||
delete,
|
||||
]
|
||||
|
||||
def get_attributes(self):
|
||||
return [
|
||||
givenName,
|
||||
sn,
|
||||
login,
|
||||
]
|
||||
|
||||
|
||||
def test_Named():
|
||||
class named_class(crud.Named):
|
||||
pass
|
||||
|
||||
n = named_class()
|
||||
assert n.name == 'named_class'
|
||||
|
||||
|
||||
def test_Command():
|
||||
class user(object):
|
||||
name = 'user'
|
||||
class add(crud.Command):
|
||||
pass
|
||||
i = add(user())
|
||||
assert i.name == 'add'
|
||||
assert i.full_name == 'add_user'
|
||||
|
||||
|
||||
def test_Object():
|
||||
i = user()
|
||||
assert i.name == 'user'
|
||||
|
||||
# Test commands:
|
||||
commands = i.commands
|
||||
assert isinstance(commands, base.NameSpace)
|
||||
assert list(commands) == ['create', 'delete', 'retrieve', 'update']
|
||||
assert len(commands) == 4
|
||||
for name in commands:
|
||||
cls = globals()[name]
|
||||
cmd = commands[name]
|
||||
assert type(cmd) is cls
|
||||
assert getattr(commands, name) is cmd
|
||||
assert cmd.name == name
|
||||
assert cmd.full_name == ('%s_user' % name)
|
||||
|
||||
# Test attributes:
|
||||
attributes = i.attributes
|
||||
assert isinstance(attributes, base.NameSpace)
|
||||
assert list(attributes) == ['givenName', 'sn', 'login']
|
||||
assert len(attributes) == 3
|
||||
for name in attributes:
|
||||
cls = globals()[name]
|
||||
attr = attributes[name]
|
||||
assert type(attr) is cls
|
||||
assert getattr(attributes, name) is attr
|
||||
assert attr.name == name
|
||||
assert attr.full_name == ('user_%s' % name)
|
||||
|
Loading…
Reference in New Issue
Block a user