Fuzzy feelings

This commit is contained in:
Jason Gerard DeRose 2009-12-17 06:16:18 -07:00 committed by Rob Crittenden
parent c3f9ec14d9
commit 29f243bf4e
8 changed files with 690 additions and 432 deletions

View File

@ -21,6 +21,7 @@
Test the `tests.util` module.
"""
import re
import util
from util import raises, TYPE, VALUE, LEN, KEYS
@ -48,12 +49,99 @@ class Prop(object):
prop = property(__get_prop, __set_prop, __del_prop)
class test_Fuzzy(object):
klass = util.Fuzzy
def test_init(self):
inst = self.klass()
assert inst.regex is None
assert inst.type is None
assert inst.test is None
assert inst.re is None
inst = self.klass('(foo|bar)')
assert inst.regex == '(foo|bar)'
assert inst.type is unicode
assert inst.test is None
assert isinstance(inst.re, re._pattern_type)
inst = self.klass('(foo|bar)', type=str)
assert inst.regex == '(foo|bar)'
assert inst.type is str
assert inst.test is None
assert isinstance(inst.re, re._pattern_type)
t = lambda other: other > 500
inst = self.klass(test=t)
assert inst.regex is None
assert inst.type is None
assert inst.test is t
assert inst.re is None
inst = self.klass(type=(int, float), test=t)
assert inst.regex is None
assert inst.type == (int, float)
assert inst.test is t
assert inst.re is None
def test_repr(self):
s = 'Fuzzy(regex=%r, type=%r, test=%r)'
t = lambda other: 0.0 <= other <= 1.0
inst = self.klass()
assert repr(inst) == s % (None, None, None)
inst = self.klass('foo')
assert repr(inst) == s % ('foo', unicode, None)
inst = self.klass(type=(int, float))
assert repr(inst) == s % (None, (int, float), None)
inst = self.klass(type=(int, float), test=t)
assert repr(inst) == s % (None, (int, float), t)
inst = self.klass(test=t)
assert repr(inst) == s % (None, None, t)
def test_eq(self):
assert (self.klass('bar') == u'foobar') is True
assert (self.klass('^bar') == u'foobar') is False
assert (self.klass('bar', type=str) == u'foobar') is False
assert ('18' == self.klass()) is True
assert ('18' == self.klass(type=int)) is False
assert (18 == self.klass(type=int)) is True
assert ('18' == self.klass(type=(int, str))) is True
assert (self.klass() == '18') is True
assert (self.klass(type=int) == '18') is False
assert (self.klass(type=int) == 18) is True
assert (self.klass(type=(int, str)) == '18') is True
t = lambda other: other.endswith('bar')
assert (self.klass(test=t) == 'foobar') is True
assert (self.klass(test=t, type=unicode) == 'foobar') is False
assert (self.klass(test=t) == 'barfoo') is False
assert (False == self.klass()) is True
assert (True == self.klass()) is True
assert (None == self.klass()) is True
def test_assert_deepequal():
f = util.assert_deepequal
# Test with good scalar values:
f(u'hello', u'hello', 'foo')
f(18, 18, 'foo')
f(u'hello', u'hello')
f(util.Fuzzy(), u'hello')
f(util.Fuzzy(type=unicode), u'hello')
f(util.Fuzzy('ell'), u'hello')
f(util.Fuzzy(test=lambda other: other.endswith('llo')), u'hello')
f(18, 18)
f(util.Fuzzy(), 18)
f(util.Fuzzy(type=int), 18)
f(util.Fuzzy(type=(int, float), test=lambda other: other > 17.9), 18)
# Test with bad scalar values:
e = raises(AssertionError, f, u'hello', u'world', 'foo')

View File

@ -21,20 +21,41 @@
Defines the expected objectclass for various entries.
"""
host = (
user = [
u'top',
u'person',
u'organizationalperson',
u'inetorgperson',
u'inetuser',
u'posixaccount',
u'krbprincipalaux',
u'radiusprofile',
u'ipaobject',
]
group = [
u'top',
u'groupofnames',
u'nestedgroup',
u'ipausergroup',
u'ipaobject',
]
host = [
u'ipaobject',
u'nshost',
u'ipahost',
u'pkiuser',
u'ipaservice',
u'krbprincipalaux',
u'krbprincipal',
u'top',
)
]
hostgroup = (
hostgroup = [
u'ipaobject',
u'ipahostgroup',
u'nestedGroup',
u'groupOfNames',
u'top',
)
]

View File

@ -21,248 +21,331 @@
Test the `ipalib/plugins/group.py` module.
"""
import sys
from xmlrpc_test import XMLRPC_test, assert_attr_equal
from ipalib import api, errors
from xmlrpc_test import Declarative
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
group_objectclass = (
u'top',
u'groupofnames',
u'nestedgroup',
u'ipausergroup',
u'ipaobject',
)
group1 = u'testgroup1'
group2 = u'testgroup2'
class test_group(Declarative):
cleanup_commands = [
('group_del', [u'testgroup1'], {}),
('group_del', [u'testgroup2'], {}),
('group_del', [group1], {}),
('group_del', [group2], {}),
]
tests = [
# testgroup1:
################
# create group1:
dict(
desc='Try to retrieve a non-existant testgroup1',
command=('group_show', [u'testgroup2'], {}),
desc='Try to retrieve non-existant %r' % group1,
command=('group_show', [group1], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Create testgroup1',
command=(
'group_add', [u'testgroup1'], dict(description=u'Test desc 1')
),
expected=dict(
value=u'testgroup1',
result=dict(
cn=(u'testgroup1',),
description=(u'Test desc 1',),
objectclass=group_objectclass,
),
summary=u'Added group "testgroup1"',
),
ignore_values=['ipauniqueid', 'dn'],
),
dict(
desc='Try to create testgroup1 again',
desc='Try to update non-existant %r' % group1,
command=('group_mod', [group1], dict(description=u'Foo')),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Try to delete non-existant %r' % group1,
command=('group_del', [group1], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Create %r' % group1,
command=(
'group_add', [u'testgroup1'], dict(description=u'Test desc 1')
'group_add', [group1], dict(description=u'Test desc 1')
),
expected=dict(
value=group1,
summary=u'Added group "testgroup1"',
result=dict(
cn=[group1],
description=[u'Test desc 1'],
objectclass=objectclasses.group,
ipauniqueid=[fuzzy_uuid],
dn=u'cn=testgroup1,cn=groups,cn=accounts,' + api.env.basedn,
),
),
),
dict(
desc='Try to create duplicate %r' % group1,
command=(
'group_add', [group1], dict(description=u'Test desc 1')
),
expected=errors.DuplicateEntry(),
),
dict(
desc='Retrieve testgroup1',
command=('group_show', [u'testgroup1'], {}),
expected=dict(
value=u'testgroup1',
result=dict(
cn=(u'testgroup1',),
description=(u'Test desc 1',),
),
summary=None,
),
ignore_values=['dn'],
),
dict(
desc='Updated testgroup1',
desc='Retrieve %r' % group1,
command=('group_show', [group1], {}),
expected=dict(
value=group1,
summary=None,
result=dict(
cn=[group1],
description=[u'Test desc 1'],
dn=u'cn=testgroup1,cn=groups,cn=accounts,' + api.env.basedn,
),
),
),
dict(
desc='Updated %r' % group1,
command=(
'group_mod', [u'testgroup1'], dict(description=u'New desc 1')
'group_mod', [group1], dict(description=u'New desc 1')
),
expected=dict(
result=dict(
description=(u'New desc 1',),
description=[u'New desc 1'],
),
summary=u'Modified group "testgroup1"',
value=u'testgroup1',
value=group1,
),
),
dict(
desc='Retrieve testgroup1 to check update',
command=('group_show', [u'testgroup1'], {}),
desc='Retrieve %r to verify update' % group1,
command=('group_show', [group1], {}),
expected=dict(
value=u'testgroup1',
value=group1,
result=dict(
cn=(u'testgroup1',),
description=(u'New desc 1',),
cn=[group1],
description=[u'New desc 1'],
dn=u'cn=testgroup1,cn=groups,cn=accounts,' + api.env.basedn,
),
summary=None,
),
ignore_values=['dn'],
),
# FIXME: The return value is totally different here than from the above
# group_mod() test. I think that for all *_mod() commands we should
# just return the entry exactly as *_show() does.
dict(
desc='Updated testgroup1 to promote it to posix group',
command=('group_mod', [u'testgroup1'], dict(posix=True)),
desc='Updated %r to promote it to a posix group' % group1,
command=('group_mod', [group1], dict(posix=True)),
expected=dict(
result=dict(
cn=(u'testgroup1',),
description=(u'New desc 1',),
objectclass=group_objectclass + (u'posixgroup',),
cn=[group1],
description=[u'New desc 1'],
objectclass=objectclasses.group + [u'posixgroup'],
ipauniqueid=[fuzzy_uuid],
gidnumber=[fuzzy_digits],
),
value=u'testgroup1',
value=group1,
summary=u'Modified group "testgroup1"',
),
ignore_values=['gidnumber', 'ipauniqueid'],
),
dict(
desc="Retrieve testgroup1 to check it's a posix group",
command=('group_show', [u'testgroup1'], {}),
desc="Retrieve %r to verify it's a posix group" % group1,
command=('group_show', [group1], {}),
expected=dict(
value=u'testgroup1',
value=group1,
result=dict(
cn=(u'testgroup1',),
cn=[group1],
description=(u'New desc 1',),
dn=u'cn=testgroup1,cn=groups,cn=accounts,' + api.env.basedn,
gidnumber=[fuzzy_digits],
),
summary=None,
),
ignore_values=['dn', 'gidnumber'],
),
dict(
desc='Search for testgroup1',
command=('group_find', [], dict(cn=u'testgroup1')),
desc='Search for %r' % group1,
command=('group_find', [], dict(cn=group1)),
expected=dict(
count=1,
truncated=False,
result=(
result=[
dict(
cn=(u'testgroup1',),
description=(u'New desc 1',),
cn=[group1],
description=[u'New desc 1'],
gidnumber=[fuzzy_digits],
),
),
],
summary=u'1 group matched',
),
ignore_values=['gidnumber'],
),
# testgroup2:
################
# create group2:
dict(
desc='Try to retrieve a non-existant testgroup2',
command=('group_show', [u'testgroup2'], {}),
desc='Try to retrieve non-existant %r' % group2,
command=('group_show', [group2], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Create testgroup2',
command=(
'group_add', [u'testgroup2'], dict(description=u'Test desc 2')
),
expected=dict(
value=u'testgroup2',
result=dict(
cn=(u'testgroup2',),
description=(u'Test desc 2',),
objectclass=group_objectclass,
),
summary=u'Added group "testgroup2"',
),
ignore_values=['ipauniqueid', 'dn'],
),
dict(
desc='Try to create testgroup2 again',
desc='Try to update non-existant %r' % group2,
command=('group_mod', [group2], dict(description=u'Foo')),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Try to delete non-existant %r' % group2,
command=('group_del', [group2], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Create %r' % group2,
command=(
'group_add', [u'testgroup2'], dict(description=u'Test desc 2')
'group_add', [group2], dict(description=u'Test desc 2')
),
expected=dict(
value=group2,
summary=u'Added group "testgroup2"',
result=dict(
cn=[group2],
description=[u'Test desc 2'],
objectclass=objectclasses.group,
ipauniqueid=[fuzzy_uuid],
dn=u'cn=testgroup2,cn=groups,cn=accounts,' + api.env.basedn,
),
),
),
dict(
desc='Try to create duplicate %r' % group2,
command=(
'group_add', [group2], dict(description=u'Test desc 2')
),
expected=errors.DuplicateEntry(),
),
dict(
desc='Retrieve testgroup2',
command=('group_show', [u'testgroup2'], {}),
desc='Retrieve %r' % group2,
command=('group_show', [group2], {}),
expected=dict(
value=u'testgroup2',
value=group2,
summary=None,
result=dict(
cn=(u'testgroup2',),
description=(u'Test desc 2',),
cn=[group2],
description=[u'Test desc 2'],
dn=u'cn=testgroup2,cn=groups,cn=accounts,' + api.env.basedn,
),
),
),
dict(
desc='Updated %r' % group2,
command=(
'group_mod', [group2], dict(description=u'New desc 2')
),
expected=dict(
result=dict(
description=[u'New desc 2'],
),
summary=u'Modified group "testgroup2"',
value=group2,
),
),
dict(
desc='Retrieve %r to verify update' % group2,
command=('group_show', [group2], {}),
expected=dict(
value=group2,
result=dict(
cn=[group2],
description=[u'New desc 2'],
dn=u'cn=testgroup2,cn=groups,cn=accounts,' + api.env.basedn,
),
summary=None,
),
ignore_values=['dn'],
),
dict(
desc='Search for testgroup2',
command=('group_find', [], dict(cn=u'testgroup2')),
desc='Search for %r' % group2,
command=('group_find', [], dict(cn=group2)),
expected=dict(
count=1,
truncated=False,
result=(
result=[
dict(
cn=(u'testgroup2',),
description=(u'Test desc 2',),
cn=[group2],
description=[u'New desc 2'],
),
),
],
summary=u'1 group matched',
),
),
dict(
desc='Updated testgroup2',
command=(
'group_mod', [u'testgroup2'], dict(description=u'New desc 2')
),
desc='Search for all groups',
command=('group_find', [], {}),
expected=dict(
result=dict(
description=(u'New desc 2',),
),
value=u'testgroup2',
summary=u'Modified group "testgroup2"',
summary=u'5 groups matched',
count=5,
truncated=False,
result=[
{
'member user': [u'admin'],
'gidnumber': [fuzzy_digits],
'cn': [u'admins'],
'description': [u'Account administrators group'],
},
{
'gidnumber': [fuzzy_digits],
'cn': [u'ipausers'],
'description': [u'Default group for all users'],
},
{
'gidnumber': [fuzzy_digits],
'cn': [u'editors'],
'description': [u'Limited admins who can edit other users'],
},
dict(
cn=[group1],
description=[u'New desc 1'],
gidnumber=[fuzzy_digits],
),
dict(
cn=[group2],
description=[u'New desc 2'],
),
],
),
),
dict(
desc='Retrieve testgroup2 to check update',
command=('group_show', [u'testgroup2'], {}),
expected=dict(
value=u'testgroup2',
result=dict(
cn=(u'testgroup2',),
description=(u'New desc 2',),
),
summary=None,
),
ignore_values=['dn'],
),
###############
# member stuff:
dict(
desc='Make testgroup2 member of testgroup1',
desc='Add member %r to %r' % (group2, group1),
command=(
'group_add_member', [u'testgroup1'], dict(group=u'testgroup2')
'group_add_member', [group1], dict(group=group2)
),
expected=dict(
completed=1,
@ -272,15 +355,15 @@ class test_group(Declarative):
user=tuple(),
),
),
result={'member group': (u'testgroup2',)},
result={'member group': (group2,)},
),
),
dict(
# FIXME: Shouldn't this raise a NotFound instead?
desc='Try to add a non-existent member to testgroup1',
desc='Try to add non-existent member to %r' % group1,
command=(
'group_add_member', [u'testgroup1'], dict(group=u'notfound')
'group_add_member', [group1], dict(group=u'notfound')
),
expected=dict(
completed=0,
@ -290,14 +373,14 @@ class test_group(Declarative):
user=tuple(),
),
),
result={'member group': (u'testgroup2',)},
result={'member group': (group2,)},
),
),
dict(
desc='Remove member testgroup2 from testgroup1',
desc='Remove member %r from %r' % (group2, group1),
command=('group_remove_member',
[u'testgroup1'], dict(group=u'testgroup2')
[group1], dict(group=group2)
),
expected=dict(
completed=1,
@ -313,9 +396,9 @@ class test_group(Declarative):
dict(
# FIXME: Shouldn't this raise a NotFound instead?
desc='Try to remove a non-existent member from testgroup1',
desc='Try to remove non-existent member from %r' % group1,
command=('group_remove_member',
[u'testgroup1'], dict(group=u'notfound')
[group1], dict(group=u'notfound')
),
expected=dict(
completed=0,
@ -330,69 +413,73 @@ class test_group(Declarative):
),
# Delete:
################
# delete group1:
dict(
desc='Delete testgroup1',
command=('group_del', [u'testgroup1'], {}),
desc='Delete %r' % group1,
command=('group_del', [group1], {}),
expected=dict(
result=True,
value=u'testgroup1',
value=group1,
summary=u'Deleted group "testgroup1"',
),
)
),
dict(
desc='Delete testgroup2',
command=('group_del', [u'testgroup2'], {}),
desc='Try to delete non-existant %r' % group1,
command=('group_del', [group1], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Try to retrieve non-existant %r' % group1,
command=('group_show', [group1], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Try to update non-existant %r' % group1,
command=('group_mod', [group1], dict(description=u'Foo')),
expected=errors.NotFound(reason='no such entry'),
),
################
# delete group2:
dict(
desc='Delete %r' % group2,
command=('group_del', [group2], {}),
expected=dict(
result=True,
value=u'testgroup2',
value=group2,
summary=u'Deleted group "testgroup2"',
),
)
),
##############
# Non-existent
##############
# testgroup1:
dict(
desc='Try to retrieve non-existent testgroup1',
command=('group_show', [u'testgroup1'], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Try to update non-existent testgroup1',
command=(
'group_mod', [u'testgroup1'], dict(description=u'New desc 1')
),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Try to delete non-existent testgroup1',
command=('group_del', [u'testgroup1'], {}),
desc='Try to delete non-existant %r' % group2,
command=('group_del', [group2], {}),
expected=errors.NotFound(reason='no such entry'),
),
# testgroup2:
dict(
desc='Try to retrieve non-existent testgroup2',
command=('group_show', [u'testgroup2'], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Try to update non-existent testgroup2',
command=(
'group_mod', [u'testgroup2'], dict(description=u'New desc 2')
),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Try to delete non-existent testgroup2',
command=('group_del', [u'testgroup2'], {}),
desc='Try to retrieve non-existant %r' % group2,
command=('group_show', [group2], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Try to update non-existant %r' % group2,
command=('group_mod', [group2], dict(description=u'Foo')),
expected=errors.NotFound(reason='no such entry'),
),
]

View File

@ -23,11 +23,12 @@ Test the `ipalib.plugins.host` module.
"""
from ipalib import api, errors
from tests.test_xmlrpc.xmlrpc_test import Declarative
from tests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid
from tests.test_xmlrpc import objectclasses
fqdn1 = u'testhost1.%s' % api.env.domain
dn1 = u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn1, api.env.basedn)
class test_host(Declarative):
@ -71,16 +72,18 @@ class test_host(Declarative):
value=fqdn1,
summary=u'Added host "%s"' % fqdn1,
result=dict(
cn=(fqdn1,), # FIXME: we should only return fqdn
fqdn=(fqdn1,),
description=(u'Test host 1',),
localityname=(u'Undisclosed location 1',),
krbprincipalname=(u'host/%s@%s' % (fqdn1, api.env.realm),),
serverhostname=(u'testhost1',),
dn=dn1,
cn=[fqdn1], # FIXME: we should only return fqdn
fqdn=[fqdn1],
description=[u'Test host 1'],
localityname=[u'Undisclosed location 1'],
krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
serverhostname=[u'testhost1'],
objectclass=objectclasses.host,
managedby=[dn1],
ipauniqueid=[fuzzy_uuid],
),
),
ignore_values=['ipauniqueid', 'dn'],
),
@ -103,12 +106,12 @@ class test_host(Declarative):
value=fqdn1,
summary=None,
result=dict(
fqdn=(fqdn1,),
description=(u'Test host 1',),
localityname=(u'Undisclosed location 1',),
dn=dn1,
fqdn=[fqdn1],
description=[u'Test host 1'],
localityname=[u'Undisclosed location 1'],
),
),
ignore_values=['dn'],
),
@ -119,20 +122,22 @@ class test_host(Declarative):
value=fqdn1,
summary=None,
result=dict(
cn=(fqdn1,),
fqdn=(fqdn1,),
description=(u'Test host 1',),
dn=dn1,
cn=[fqdn1],
fqdn=[fqdn1],
description=[u'Test host 1'],
# FIXME: Why is 'localalityname' returned as 'l' with --all?
# It is intuitive for --all to return additional attributes,
# but not to return existing attributes under different
# names.
l=(u'Undisclosed location 1',),
krbprincipalname=(u'host/%s@%s' % (fqdn1, api.env.realm),),
serverhostname=(u'testhost1',),
l=[u'Undisclosed location 1'],
krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
serverhostname=[u'testhost1'],
objectclass=objectclasses.host,
managedby=[dn1],
ipauniqueid=[fuzzy_uuid],
),
),
ignore_values=['dn', 'ipauniqueid'],
),
@ -143,13 +148,13 @@ class test_host(Declarative):
count=1,
truncated=False,
summary=u'1 host matched',
result=(
result=[
dict(
fqdn=(fqdn1,),
description=(u'Test host 1',),
localityname=(u'Undisclosed location 1',),
fqdn=[fqdn1],
description=[u'Test host 1'],
localityname=[u'Undisclosed location 1'],
),
),
],
),
),
@ -161,25 +166,24 @@ class test_host(Declarative):
count=1,
truncated=False,
summary=u'1 host matched',
result=(
result=[
dict(
cn=(fqdn1,),
fqdn=(fqdn1,),
description=(u'Test host 1',),
cn=[fqdn1],
fqdn=[fqdn1],
description=[u'Test host 1'],
# FIXME: Why is 'localalityname' returned as 'l' with --all?
# It is intuitive for --all to return additional attributes,
# but not to return existing attributes under different
# names.
l=(u'Undisclosed location 1',),
krbprincipalname=(u'host/%s@%s' % (fqdn1, api.env.realm),),
serverhostname=(u'testhost1',),
l=[u'Undisclosed location 1'],
krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
serverhostname=[u'testhost1'],
objectclass=objectclasses.host,
managedby=[dn1],
ipauniqueid=[fuzzy_uuid],
),
),
],
),
# FIXME: With --all, host_show() returns the 'dn', but host_find()
# doesn't.
ignore_values=['ipauniqueid'],
),
@ -190,7 +194,7 @@ class test_host(Declarative):
value=fqdn1,
summary=u'Modified host "%s"' % fqdn1,
result=dict(
description=(u'Updated host 1',),
description=[u'Updated host 1'],
),
),
),
@ -203,12 +207,12 @@ class test_host(Declarative):
value=fqdn1,
summary=None,
result=dict(
fqdn=(fqdn1,),
description=(u'Updated host 1',),
localityname=(u'Undisclosed location 1',),
dn=dn1,
fqdn=[fqdn1],
description=[u'Updated host 1'],
localityname=[u'Undisclosed location 1'],
),
),
ignore_values=['dn'],
),

View File

@ -23,32 +23,35 @@ Test the `ipalib.plugins.hostgroup` module.
"""
from ipalib import api, errors
from tests.test_xmlrpc.xmlrpc_test import Declarative
from tests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid
from tests.test_xmlrpc import objectclasses
hostgroup1 = u'testhostgroup1'
dn1 = u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn)
fqdn1 = u'testhost1.%s' % api.env.domain
host_dn1 = u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn1, api.env.basedn)
class test_hostgroup(Declarative):
cleanup_commands = [
('hostgroup_del', [u'testhostgroup1'], {}),
('hostgroup_del', [hostgroup1], {}),
('host_del', [fqdn1], {}),
]
tests=[
dict(
desc='Try to retrieve non-existent testhostgroup1',
command=('hostgroup_show', [u'testhostgroup1'], {}),
desc='Try to retrieve non-existent %r' % hostgroup1,
command=('hostgroup_show', [hostgroup1], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Try to update non-existent testhostgroup1',
command=('hostgroup_mod', [u'testhostgroup1'],
desc='Try to update non-existent %r' % hostgroup1,
command=('hostgroup_mod', [hostgroup1],
dict(description=u'Updated hostgroup 1')
),
expected=errors.NotFound(reason='no such entry'),
@ -56,33 +59,34 @@ class test_hostgroup(Declarative):
dict(
desc='Try to delete non-existent testhostgroup1',
command=('hostgroup_del', [u'testhostgroup1'], {}),
desc='Try to delete non-existent %r' % hostgroup1,
command=('hostgroup_del', [hostgroup1], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Create hostgroup testhostgroup1',
command=('hostgroup_add', [u'testhostgroup1'],
desc='Create %r' % hostgroup1,
command=('hostgroup_add', [hostgroup1],
dict(description=u'Test hostgroup 1')
),
expected=dict(
value=u'testhostgroup1',
value=hostgroup1,
summary=u'Added hostgroup "testhostgroup1"',
result=dict(
cn=(u'testhostgroup1',),
dn=dn1,
cn=[hostgroup1],
objectclass=objectclasses.hostgroup,
description=(u'Test hostgroup 1',),
description=[u'Test hostgroup 1'],
ipauniqueid=[fuzzy_uuid],
),
),
ignore_values=['ipauniqueid', 'dn'],
),
dict(
desc='Try to create duplicate testhostgroup1',
command=('hostgroup_add', [u'testhostgroup1'],
desc='Try to create duplicate %r' % hostgroup1,
command=('hostgroup_add', [hostgroup1],
dict(description=u'Test hostgroup 1')
),
expected=errors.DuplicateEntry(),
@ -101,23 +105,25 @@ class test_hostgroup(Declarative):
value=fqdn1,
summary=u'Added host "%s"' % fqdn1,
result=dict(
cn=(fqdn1,), # FIXME: we should only return fqdn
fqdn=(fqdn1,),
description=(u'Test host 1',),
localityname=(u'Undisclosed location 1',),
krbprincipalname=(u'host/%s@%s' % (fqdn1, api.env.realm),),
serverhostname=(u'testhost1',),
dn=host_dn1,
cn=[fqdn1], # FIXME: we should only return fqdn
fqdn=[fqdn1],
description=[u'Test host 1'],
localityname=[u'Undisclosed location 1'],
krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
serverhostname=[u'testhost1'],
objectclass=objectclasses.host,
managedby=[host_dn1],
ipauniqueid=[fuzzy_uuid],
),
),
ignore_values=['ipauniqueid', 'dn'],
),
dict(
desc=u'Add %r to testhostgroup1' % fqdn1,
desc=u'Add host %r to %r' % (fqdn1, hostgroup1),
command=(
'hostgroup_add_member', [u'testhostgroup1'], dict(host=fqdn1)
'hostgroup_add_member', [hostgroup1], dict(host=fqdn1)
),
expected=dict(
completed=1,
@ -128,80 +134,80 @@ class test_hostgroup(Declarative):
),
),
result={
'member host': (fqdn1,),
'member host': [fqdn1],
},
),
),
dict(
desc='Retrieve testhostgroup1',
command=('hostgroup_show', [u'testhostgroup1'], {}),
desc='Retrieve %r' % hostgroup1,
command=('hostgroup_show', [hostgroup1], {}),
expected=dict(
value=u'testhostgroup1',
value=hostgroup1,
summary=None,
result={
'member host': (u'testhost1.example.com',),
'cn': (u'testhostgroup1',),
'description': (u'Test hostgroup 1',)
'dn': dn1,
'member host': [u'testhost1.example.com'],
'cn': [hostgroup1],
'description': [u'Test hostgroup 1'],
},
),
ignore_values=['dn'],
),
dict(
desc='Search for testhostgroup1',
command=('hostgroup_find', [], dict(cn=u'testhostgroup1')),
desc='Search for %r' % hostgroup1,
command=('hostgroup_find', [], dict(cn=hostgroup1)),
expected=dict(
count=1,
truncated=False,
summary=u'1 hostgroup matched',
result=(
result=[
{
'member host': (u'testhost1.example.com',),
'cn': (u'testhostgroup1',),
'description': (u'Test hostgroup 1',),
'member host': [u'testhost1.example.com'],
'cn': [hostgroup1],
'description': [u'Test hostgroup 1'],
},
),
],
),
),
dict(
desc='Update testhostgroup1',
command=('hostgroup_mod', [u'testhostgroup1'],
desc='Update %r' % hostgroup1,
command=('hostgroup_mod', [hostgroup1],
dict(description=u'Updated hostgroup 1')
),
expected=dict(
value=u'testhostgroup1',
value=hostgroup1,
summary=u'Modified hostgroup "testhostgroup1"',
result=dict(
description=(u'Updated hostgroup 1',),
description=[u'Updated hostgroup 1'],
),
),
),
dict(
desc='Retrieve testhostgroup1 to verify update',
command=('hostgroup_show', [u'testhostgroup1'], {}),
desc='Retrieve %r to verify update' % hostgroup1,
command=('hostgroup_show', [hostgroup1], {}),
expected=dict(
value=u'testhostgroup1',
value=hostgroup1,
summary=None,
result={
'member host': (u'testhost1.example.com',),
'cn': (u'testhostgroup1',),
'description': (u'Updated hostgroup 1',)
'dn': dn1,
'member host': [u'testhost1.example.com'],
'cn': [hostgroup1],
'description': [u'Updated hostgroup 1'],
},
),
ignore_values=['dn'],
),
dict(
desc='Remove %s from testhostgroup1',
command=('hostgroup_remove_member', [u'testhostgroup1'],
desc='Remove host %r from %r' % (fqdn1, hostgroup1),
command=('hostgroup_remove_member', [hostgroup1],
dict(host=fqdn1)
),
expected=dict(
@ -218,10 +224,10 @@ class test_hostgroup(Declarative):
dict(
desc='Delete testhostgroup1',
command=('hostgroup_del', [u'testhostgroup1'], {}),
desc='Delete %r' % hostgroup1,
command=('hostgroup_del', [hostgroup1], {}),
expected=dict(
value=u'testhostgroup1',
value=hostgroup1,
summary=u'Deleted hostgroup "testhostgroup1"',
result=True,
),
@ -229,7 +235,7 @@ class test_hostgroup(Declarative):
dict(
desc='Delete %s' % fqdn1,
desc='Delete host %r' % fqdn1,
command=('host_del', [fqdn1], {}),
expected=dict(
value=fqdn1,

View File

@ -24,66 +24,71 @@ Test the `ipalib/plugins/user.py` module.
"""
from ipalib import api, errors
from xmlrpc_test import Declarative
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
user_objectclass = (
u'top',
u'person',
u'organizationalperson',
u'inetorgperson',
u'inetuser',
u'posixaccount',
u'krbprincipalaux',
u'radiusprofile',
u'ipaobject',
)
user_memberof = (u'cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com',)
user1=u'tuser1'
class test_user(Declarative):
cleanup_commands = [
('user_del', [u'tuser1'], {}),
('user_del', [user1], {}),
]
tests = [
dict(
desc='Try to retrieve non-existant user',
command=(
'user_show', [u'tuser1'], {}
),
desc='Try to retrieve non-existent %r' % user1,
command=('user_show', [user1], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Create a user',
command=(
'user_add', [], dict(givenname=u'Test', sn=u'User1')
),
expected=dict(
value=u'tuser1',
result=dict(
cn=(u'Test User1',),
gecos=(u'tuser1',),
givenname=(u'Test',),
homedirectory=(u'/home/tuser1',),
krbprincipalname=(u'tuser1@' + api.env.realm,),
loginshell=(u'/bin/sh',),
objectclass=user_objectclass,
sn=(u'User1',),
uid=(u'tuser1',),
),
summary=u'Added user "tuser1"',
),
ignore_values=['ipauniqueid', 'gidnumber', 'dn'],
desc='Try to update non-existent %r' % user1,
command=('user_mod', [user1], dict(givenname=u'Foo')),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Try to create another user with same login',
desc='Try to delete non-existent %r' % user1,
command=('user_del', [user1], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Create %r' % user1,
command=(
'user_add', [], dict(givenname=u'Test', sn=u'User1')
),
expected=dict(
value=user1,
summary=u'Added user "tuser1"',
result=dict(
cn=[u'Test User1'],
gecos=[user1],
givenname=[u'Test'],
homedirectory=[u'/home/tuser1'],
krbprincipalname=[u'tuser1@' + api.env.realm],
loginshell=[u'/bin/sh'],
objectclass=objectclasses.user,
sn=[u'User1'],
uid=[user1],
gidnumber=[fuzzy_digits],
ipauniqueid=[fuzzy_uuid],
dn=u'uid=tuser1,cn=users,cn=accounts,' + api.env.basedn,
),
),
),
dict(
desc='Try to create duplicate %r' % user1,
command=(
'user_add', [], dict(givenname=u'Test', sn=u'User1')
),
@ -92,68 +97,70 @@ class test_user(Declarative):
dict(
desc='Retrieve the user',
desc='Retrieve %r' % user1,
command=(
'user_show', [u'tuser1'], {}
'user_show', [user1], {}
),
expected=dict(
result=dict(
dn=u'uid=tuser1,cn=users,cn=accounts,dc=example,dc=com',
givenname=(u'Test',),
homedirectory=(u'/home/tuser1',),
loginshell=(u'/bin/sh',),
sn=(u'User1',),
uid=(u'tuser1',),
givenname=[u'Test'],
homedirectory=[u'/home/tuser1'],
loginshell=[u'/bin/sh'],
sn=[u'User1'],
uid=[user1],
),
value=u'tuser1',
value=user1,
summary=None,
),
),
dict(
desc='Search for this user with all=True',
desc='Search for %r with all=True' % user1,
command=(
'user_find', [u'tuser1'], {'all': True}
'user_find', [user1], {'all': True}
),
expected=dict(
result=(
result=[
{
'cn': (u'Test User1',),
'gecos': (u'tuser1',),
'givenname': (u'Test',),
'homedirectory': (u'/home/tuser1',),
'krbprincipalname': (u'tuser1@' + api.env.realm,),
'loginshell': (u'/bin/sh',),
'memberof group': (u'ipausers',),
'objectclass': user_objectclass,
'sn': (u'User1',),
'uid': (u'tuser1',),
'cn': [u'Test User1'],
'gecos': [user1],
'givenname': [u'Test'],
'homedirectory': [u'/home/tuser1'],
'krbprincipalname': [u'tuser1@' + api.env.realm],
'loginshell': [u'/bin/sh'],
'memberof group': [u'ipausers'],
'objectclass': objectclasses.user,
'sn': [u'User1'],
'uid': [user1],
'uidnumber': [fuzzy_digits],
'gidnumber': [fuzzy_digits],
'ipauniqueid': [fuzzy_uuid],
},
),
],
summary=u'1 user matched',
count=1,
truncated=False,
),
ignore_values=['uidnumber', 'gidnumber', 'ipauniqueid'],
),
dict(
desc='Search for this user with minimal attributes',
desc='Search for %r with minimal attributes' % user1,
command=(
'user_find', [u'tuser1'], {}
'user_find', [user1], {}
),
expected=dict(
result=(
result=[
dict(
givenname=(u'Test',),
homedirectory=(u'/home/tuser1',),
loginshell=(u'/bin/sh',),
sn=(u'User1',),
uid=(u'tuser1',),
givenname=[u'Test'],
homedirectory=[u'/home/tuser1'],
loginshell=[u'/bin/sh'],
sn=[u'User1'],
uid=[user1],
),
),
],
summary=u'1 user matched',
count=1,
truncated=False,
@ -167,21 +174,21 @@ class test_user(Declarative):
'user_find', [], {}
),
expected=dict(
result=(
result=[
dict(
homedirectory=(u'/home/admin',),
loginshell=(u'/bin/bash',),
sn=(u'Administrator',),
uid=(u'admin',),
homedirectory=[u'/home/admin'],
loginshell=[u'/bin/bash'],
sn=[u'Administrator'],
uid=[u'admin'],
),
dict(
givenname=(u'Test',),
homedirectory=(u'/home/tuser1',),
loginshell=(u'/bin/sh',),
sn=(u'User1',),
uid=(u'tuser1',),
givenname=[u'Test'],
homedirectory=[u'/home/tuser1'],
loginshell=[u'/bin/sh'],
sn=[u'User1'],
uid=[user1],
),
),
],
summary=u'2 users matched',
count=2,
truncated=False,
@ -190,95 +197,95 @@ class test_user(Declarative):
dict(
desc='Lock user',
desc='Lock %r' % user1,
command=(
'user_lock', [u'tuser1'], {}
'user_lock', [user1], {}
),
expected=dict(
result=True,
value=u'tuser1',
value=user1,
summary=u'Locked user "tuser1"',
),
),
dict(
desc='Unlock user',
desc='Unlock %r' % user1,
command=(
'user_unlock', [u'tuser1'], {}
'user_unlock', [user1], {}
),
expected=dict(
result=True,
value=u'tuser1',
value=user1,
summary=u'Unlocked user "tuser1"',
),
),
dict(
desc='Update user',
desc='Update %r' % user1,
command=(
'user_mod', [u'tuser1'], dict(givenname=u'Finkle')
'user_mod', [user1], dict(givenname=u'Finkle')
),
expected=dict(
result=dict(
givenname=(u'Finkle',),
givenname=[u'Finkle'],
),
summary=u'Modified user "tuser1"',
value=u'tuser1',
value=user1,
),
),
dict(
desc='Retrieve user to verify update',
command=(
'user_show', [u'tuser1'], {}
),
desc='Retrieve %r to verify update' % user1,
command=('user_show', [user1], {}),
expected=dict(
result=dict(
dn=u'uid=tuser1,cn=users,cn=accounts,dc=example,dc=com',
givenname=(u'Finkle',),
homedirectory=(u'/home/tuser1',),
loginshell=(u'/bin/sh',),
sn=(u'User1',),
uid=(u'tuser1',),
givenname=[u'Finkle'],
homedirectory=[u'/home/tuser1'],
loginshell=[u'/bin/sh'],
sn=[u'User1'],
uid=[user1],
),
summary=None,
value=u'tuser1',
value=user1,
),
),
dict(
desc='Delete user',
command=(
'user_del', [u'tuser1'], {}
),
desc='Delete %r' % user1,
command=('user_del', [user1], {}),
expected=dict(
result=True,
summary=u'Deleted user "tuser1"',
value=u'tuser1',
value=user1,
),
),
dict(
desc='Do double delete',
command=(
'user_del', [u'tuser1'], {}
),
desc='Try to delete non-existent %r' % user1,
command=('user_del', [user1], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Verify user is gone',
command=(
'user_show', [u'tuser1'], {}
),
desc='Try to retrieve non-existent %r' % user1,
command=('user_show', [user1], {}),
expected=errors.NotFound(reason='no such entry'),
),
dict(
desc='Try to update non-existent %r' % user1,
command=('user_mod', [user1], dict(givenname=u'Foo')),
expected=errors.NotFound(reason='no such entry'),
),
]

View File

@ -24,11 +24,22 @@ Base class for all XML-RPC tests
import sys
import socket
import nose
from tests.util import assert_deepequal
from tests.util import assert_deepequal, Fuzzy
from ipalib import api, request
from ipalib import errors
# Matches a gidnumber like '1391016742'
# FIXME: Does it make more sense to return gidnumber, uidnumber, etc. as `int`
# or `long`? If not, we still need to return them as `unicode` instead of `str`.
fuzzy_digits = Fuzzy('^\d+$', type=str)
# Matches an ipauniqueid like u'784d85fd-eae7-11de-9d01-54520012478b'
fuzzy_uuid = Fuzzy(
'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
)
try:
if not api.Backend.xmlclient.isconnected():
api.Backend.xmlclient.connect()
@ -146,10 +157,10 @@ class Declarative(XMLRPC_test):
tests = tuple()
def cleanup_generate(self, stage):
for command in self.cleanup_commands:
for (i, command) in enumerate(self.cleanup_commands):
func = lambda: self.cleanup(command)
func.description = '%s %s-cleanup: %r' % (
self.__class__.__name__, stage, command
func.description = '%s %s-cleanup[%d]: %r' % (
self.__class__.__name__, stage, i, command
)
yield (func,)
@ -194,11 +205,10 @@ class Declarative(XMLRPC_test):
if cmd not in api.Command:
raise nose.SkipTest('%r not in api.Command' % cmd)
expected = test['expected']
ignore_values = test.get('ignore_values')
if isinstance(expected, errors.PublicError):
self.check_exception(nice, cmd, args, options, expected)
else:
self.check_output(nice, cmd, args, options, expected, ignore_values)
self.check_output(nice, cmd, args, options, expected)
def check_exception(self, nice, cmd, args, options, expected):
klass = expected.__class__
@ -224,28 +234,6 @@ class Declarative(XMLRPC_test):
# KWARGS % (cmd, name, args, options, expected.kw, e.kw)
# )
def check_output(self, nice, cmd, args, options, expected, ignore_values):
def check_output(self, nice, cmd, args, options, expected):
got = api.Command[cmd](*args, **options)
result = got['result']
if ignore_values:
if isinstance(result, dict):
self.clean_entry(
nice, cmd, args, options, result, ignore_values
)
elif isinstance(result, (list, tuple)):
for entry in result:
self.clean_entry(
nice, cmd, args, options, entry, ignore_values
)
assert_deepequal(expected, got, nice)
def clean_entry(self, nice, cmd, args, options, entry, ignore_values):
"""
Remove attributes like 'ipauniqueid' whose value is unpredictable.
"""
for key in ignore_values:
if key not in entry:
raise AssertionError(
IGNORE % (cmd, key, args, options, entry)
)
entry.pop(key)

View File

@ -26,6 +26,7 @@ import os
from os import path
import tempfile
import shutil
import re
import ipalib
from ipalib.plugable import Plugin
from ipalib.request import context
@ -108,6 +109,58 @@ def assert_equal(val1, val2):
assert val1 == val2, '%r != %r' % (val1, val2)
class Fuzzy(object):
"""
Perform a fuzzy (non-strict) equality test.
`Fuzzy` instances will likely be used when comparing nesting data-structures
using `assert_deepequal()`.
"""
def __init__(self, regex=None, type=None, test=None):
"""
Initialize.
:param regex: A regular expression pattern to match, e.g.
``u'^\d+foo'``
:param type: A type or tuple of types to test using ``isinstance()``,
e.g. ``(int, float)``
:param test: A callable used to perform equality test, e.g.
``lambda other: other >= 18``
"""
assert regex is None or isinstance(regex, basestring)
assert test is None or callable(test)
if regex is None:
self.re = None
else:
self.re = re.compile(regex)
if type is None:
type = unicode
assert type in (unicode, str)
self.regex = regex
self.type = type
self.test = test
def __repr__(self):
return '%s(regex=%r, type=%r, test=%r)' % (
self.__class__.__name__, self.regex, self.type, self.test
)
def __eq__(self, other):
if not (self.type is None or isinstance(other, self.type)):
return False
if not (self.re is None or self.re.search(other)):
return False
if not (self.test is None or self.test(other)):
return False
return True
def __ne__(self, other):
return not self.__eq__(other)
VALUE = """assert_deepequal: expected != got.
%s
expected = %r
@ -160,7 +213,11 @@ def assert_deepequal(expected, got, src='', stack=tuple()):
got = 'nurse'
path = (1, 'naughty')
"""
if type(expected) is not type(got):
if isinstance(expected, tuple):
expected = list(expected)
if isinstance(got, tuple):
got = list(got)
if not (isinstance(expected, Fuzzy) or type(expected) is type(got)):
raise AssertionError(
TYPE % (src, type(expected), type(got), expected, got, stack)
)
@ -184,7 +241,7 @@ def assert_deepequal(expected, got, src='', stack=tuple()):
e_sub = expected[key]
g_sub = got[key]
assert_deepequal(e_sub, g_sub, src, stack + (key,))
if expected != got:
elif expected != got:
raise AssertionError(
VALUE % (src, expected, got, stack)
)