diff options
Diffstat (limited to 'ipatests')
-rw-r--r-- | ipatests/test_xmlrpc/test_group_plugin.py | 1756 | ||||
-rw-r--r-- | ipatests/test_xmlrpc/test_stageuser_plugin.py | 4 | ||||
-rw-r--r-- | ipatests/test_xmlrpc/tracker/group_plugin.py | 159 |
3 files changed, 754 insertions, 1165 deletions
diff --git a/ipatests/test_xmlrpc/test_group_plugin.py b/ipatests/test_xmlrpc/test_group_plugin.py index 6eb57c12f..41d28f1cf 100644 --- a/ipatests/test_xmlrpc/test_group_plugin.py +++ b/ipatests/test_xmlrpc/test_group_plugin.py @@ -1,6 +1,7 @@ # Authors: # Rob Crittenden <rcritten@redhat.com> # Pavel Zuna <pzuna@redhat.com> +# Filip Skola <fskola@redhat.com> # # Copyright (C) 2008 Red Hat # see file 'COPYING' for use and warranty information @@ -23,1141 +24,666 @@ Test the `ipalib/plugins/group.py` module. import pytest -from ipalib import api, errors +from ipalib import errors from ipatests.test_xmlrpc import objectclasses from ipatests.test_xmlrpc.xmlrpc_test import ( - Declarative, - fuzzy_digits, - fuzzy_uuid, - fuzzy_set_ci, - add_sid, - add_oc) -from ipapython.dn import DN -from ipatests.test_xmlrpc.test_user_plugin import get_user_result + fuzzy_digits, fuzzy_uuid, fuzzy_set_ci, add_oc, + XMLRPC_test, raises_exact +) +from ipatests.test_xmlrpc.tracker.group_plugin import GroupTracker +from ipatests.test_xmlrpc.tracker.user_plugin import UserTracker +from ipatests.util import assert_deepequal, get_group_dn + +notagroup = u'notagroup' +renamedgroup1 = u'renamedgroup' +invalidgroup1 = u'+tgroup1' +external_sid1 = u'S-1-1-123456-789-1' + + +@pytest.fixture(scope='class') +def group(request): + tracker = GroupTracker(name=u'testgroup1', description=u'Test desc1') + return tracker.make_fixture(request) + + +@pytest.fixture(scope='class') +def group2(request): + tracker = GroupTracker(name=u'testgroup2', description=u'Test desc2') + return tracker.make_fixture(request) + + +@pytest.fixture(scope='class') +def managed_group(request, user): + user.ensure_exists() + tracker = GroupTracker( + name=user.uid, description=u'User private group for %s' % user.uid + ) + tracker.exists = True + # Managed group gets created when user is created + tracker.track_create() + return tracker + + +@pytest.fixture(scope='class') +def user(request): + tracker = UserTracker(name=u'user1', givenname=u'Test', sn=u'User1') + return tracker.make_fixture(request) + + +@pytest.fixture(scope='class') +def user_npg2(request, group): + """ User tracker fixture for testing users with no private group """ + tracker = UserTracker(name=u'npguser2', givenname=u'Npguser', + sn=u'Npguser2', noprivate=True, gidnumber=1000) + tracker.track_create() + del tracker.attrs['mepmanagedentry'] + tracker.attrs.update( + gidnumber=[u'1000'], description=[], memberof_group=[group.cn], + objectclass=add_oc(objectclasses.user_base, u'ipantuserattrs') + ) + return tracker.make_fixture(request) + + +@pytest.fixture(scope='class') +def admins(request): + # Track the admins group + tracker = GroupTracker( + name=u'admins', description=u'Account administrators group' + ) + tracker.exists = True + tracker.track_create() + tracker.attrs.update(member_user=[u'admin']) + return tracker + + +@pytest.fixture(scope='class') +def trustadmins(request): + # Track the 'trust admins' group + tracker = GroupTracker( + name=u'trust admins', description=u'Trusts administrators group' + ) + tracker.exists = True + tracker.track_create() + tracker.attrs.update(member_user=[u'admin']) + return tracker -group1 = u'testgroup1' -group2 = u'testgroup2' -group3 = u'testgroup3' -renamedgroup1 = u'testgroup' -user1 = u'tuser1' - -invalidgroup1=u'+tgroup1' - -# When adding external SID member to a group we can't test -# it fully due to possibly missing Samba 4 python bindings -# and/or not configured AD trusts. Thus, we'll use incorrect -# SID value to merely test that proper exceptions are raised -external_sid1=u'S-1-1-123456-789-1' - -def get_group_dn(cn): - return DN(('cn', cn), api.env.container_group, api.env.basedn) +@pytest.mark.tier1 +class TestGroup(XMLRPC_test): + def test_create(self, group): + """ Create a group """ + group.create() + + def test_create_duplicate(self, group): + """ Try to create a duplicate group """ + group.ensure_exists() + command = group.make_create_command() + + with raises_exact(errors.DuplicateEntry( + message=u'group with name "%s" already exists' % group.cn)): + command() + + def test_retrieve(self, group): + """ Retrieve a group """ + group.retrieve() + + def test_update(self, group): + """ Update a group with new description + and perform retrieve command to verify the update """ + group.update(dict(description=u'New desc')) + group.retrieve() + + def test_rename(self, group): + """ Rename a group and than rename it back """ + origname = group.cn + + command = group.make_command('group_mod', *[group.cn], + **dict(setattr=u'cn=%s' % renamedgroup1)) + result = command() + group.attrs.update(cn=[renamedgroup1]) + group.check_update(result) + group.cn = renamedgroup1 + + command = group.make_command('group_mod', *[group.cn], + **dict(setattr=u'cn=%s' % origname)) + result = command() + group.attrs.update(cn=[origname]) + group.check_update(result) + group.cn = origname + + def test_convert_posix_to_external(self, group): + """ Try to convert a posix group to external """ + command = group.make_update_command(dict(external=True)) + with raises_exact(errors.PosixGroupViolation( + reason=u"""This is already a posix group and cannot + be converted to external one""")): + command() + + def test_add_with_invalid_name(self, group): + """ Try to add group with an invalid name """ + command = group.make_command( + 'group_add', *[invalidgroup1], **dict(description=u'Test') + ) + with raises_exact(errors.ValidationError( + name='group_name', + error=u'may only include letters, numbers, _, -, . and $')): + command() @pytest.mark.tier1 -class test_group(Declarative): - cleanup_commands = [ - ('group_del', [group1], {}), - ('group_del', [group2], {}), - ('group_del', [group3], {}), - ('group_del', [renamedgroup1], {}), - ('user_del', [user1], {}), - ] - - tests = [ - - ################ - # create group1: - dict( - desc='Try to retrieve non-existent %r' % group1, - command=('group_show', [group1], {}), - expected=errors.NotFound(reason=u'%s: group not found' % group1), - ), - - - dict( - desc='Try to update non-existent %r' % group1, - command=('group_mod', [group1], dict(description=u'Foo')), - expected=errors.NotFound(reason=u'%s: group not found' % group1), - ), - - - dict( - desc='Try to delete non-existent %r' % group1, - command=('group_del', [group1], {}), - expected=errors.NotFound(reason=u'%s: group not found' % group1), - ), - - - dict( - desc='Try to rename non-existent %r' % group1, - command=('group_mod', [group1], dict(setattr=u'cn=%s' % renamedgroup1)), - expected=errors.NotFound(reason=u'%s: group not found' % group1), - ), - - - dict( - desc='Create non-POSIX %r' % group1, - command=( - 'group_add', [group1], dict(description=u'Test desc 1',nonposix=True) - ), - 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=get_group_dn('testgroup1'), - ), - ), - ), - - - dict( - desc='Try to create duplicate %r' % group1, - command=( - 'group_add', [group1], dict(description=u'Test desc 1') - ), - expected=errors.DuplicateEntry( - message=u'group with name "%s" already exists' % group1), - ), - - - dict( - desc='Retrieve non-POSIX %r' % group1, - command=('group_show', [group1], {}), - expected=dict( - value=group1, - summary=None, - result=dict( - cn=[group1], - description=[u'Test desc 1'], - dn=get_group_dn('testgroup1'), - ), - ), - ), - - - dict( - desc='Updated non-POSIX %r' % group1, - command=( - 'group_mod', [group1], dict(description=u'New desc 1') - ), - expected=dict( - result=dict( - cn=[group1], - description=[u'New desc 1'], - ), - summary=u'Modified group "testgroup1"', - value=group1, - ), - ), - - - dict( - desc='Retrieve %r to verify update' % group1, - command=('group_show', [group1], {}), - expected=dict( - value=group1, - result=dict( - cn=[group1], - description=[u'New desc 1'], - dn=get_group_dn('testgroup1'), - ), - summary=None, - ), - ), - - - # 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 %r to promote it to a POSIX group' % group1, - command=('group_mod', [group1], dict(posix=True)), - expected=dict( - result=dict( - cn=[group1], - description=[u'New desc 1'], - gidnumber=[fuzzy_digits], - ), - value=group1, - summary=u'Modified group "testgroup1"', - ), - ), - - - dict( - desc="Retrieve %r to verify it's a POSIX group" % group1, - command=('group_show', [group1], {}), - expected=dict( - value=group1, - result=dict( - cn=[group1], - description=(u'New desc 1',), - dn=get_group_dn('testgroup1'), - gidnumber=[fuzzy_digits], - ), - summary=None, - ), - ), - - - dict( - desc='Search for %r' % group1, - command=('group_find', [], dict(cn=group1)), - expected=dict( - count=1, - truncated=False, - result=[ - dict( - dn=get_group_dn(group1), - cn=[group1], - description=[u'New desc 1'], - gidnumber=[fuzzy_digits], - ), - ], - summary=u'1 group matched', - ), - ), - - - - ################ - # create group2: - dict( - desc='Try to retrieve non-existent %r' % group2, - command=('group_show', [group2], {}), - expected=errors.NotFound(reason=u'%s: group not found' % group2), - ), - - - dict( - desc='Try to update non-existent %r' % group2, - command=('group_mod', [group2], dict(description=u'Foo')), - expected=errors.NotFound(reason=u'%s: group not found' % group2), - ), - - - dict( - desc='Try to delete non-existent %r' % group2, - command=('group_del', [group2], {}), - expected=errors.NotFound(reason=u'%s: group not found' % group2), - ), - - - dict( - desc='Create %r' % group2, - command=( - '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'], - gidnumber=[fuzzy_digits], - objectclass=objectclasses.posixgroup, - ipauniqueid=[fuzzy_uuid], - dn=get_group_dn('testgroup2'), - ), - ), - ), - - - dict( - desc='Try to create duplicate %r' % group2, - command=( - 'group_add', [group2], dict(description=u'Test desc 2') - ), - expected=errors.DuplicateEntry( - message=u'group with name "%s" already exists' % group2), - ), - - - dict( - desc='Retrieve %r' % group2, - command=('group_show', [group2], {}), - expected=dict( - value=group2, - summary=None, - result=dict( - cn=[group2], - description=[u'Test desc 2'], - gidnumber=[fuzzy_digits], - dn=get_group_dn('testgroup2'), - ), - ), - ), - - - dict( - desc='Updated %r' % group2, - command=( - 'group_mod', [group2], dict(description=u'New desc 2') - ), - expected=dict( - result=dict( - cn=[group2], - gidnumber=[fuzzy_digits], - 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'], - gidnumber=[fuzzy_digits], - dn=get_group_dn('testgroup2'), - ), - summary=None, - ), - ), - - - dict( - desc='Search for %r' % group2, - command=('group_find', [], dict(cn=group2)), - expected=dict( - count=1, - truncated=False, - result=[ - dict( - dn=get_group_dn('testgroup2'), - cn=[group2], - description=[u'New desc 2'], - gidnumber=[fuzzy_digits], - ), - ], - summary=u'1 group matched', - ), - ), - - - dict( - desc='Search for all groups', - command=('group_find', [], {}), - expected=dict( - summary=u'6 groups matched', - count=6, - truncated=False, - result=[ - { - 'dn': get_group_dn('admins'), - 'member_user': [u'admin'], - 'gidnumber': [fuzzy_digits], - 'cn': [u'admins'], - 'description': [u'Account administrators group'], - }, - { - 'dn': get_group_dn('editors'), - 'gidnumber': [fuzzy_digits], - 'cn': [u'editors'], - 'description': [u'Limited admins who can edit other users'], - }, - { - 'dn': get_group_dn('ipausers'), - 'cn': [u'ipausers'], - 'description': [u'Default group for all users'], - }, - dict( - dn=get_group_dn(group1), - cn=[group1], - description=[u'New desc 1'], - gidnumber=[fuzzy_digits], - ), - dict( - dn=get_group_dn(group2), - cn=[group2], - description=[u'New desc 2'], - gidnumber=[fuzzy_digits], - ), - { - 'dn': get_group_dn('trust admins'), - 'member_user': [u'admin'], - 'cn': [u'trust admins'], - 'description': [u'Trusts administrators group'], - }, - ], - ), - ), - - dict( - desc='Search for non-POSIX groups', - command=('group_find', [], dict(nonposix=True, all=True)), - expected=dict( - summary=u'2 groups matched', - count=2, - truncated=False, - result=[ - { - 'dn': get_group_dn('ipausers'), - 'cn': [u'ipausers'], - 'description': [u'Default group for all users'], - 'objectclass': fuzzy_set_ci(objectclasses.group), - 'ipauniqueid': [fuzzy_uuid], - }, - { - 'dn': get_group_dn('trust admins'), - 'member_user': [u'admin'], - 'cn': [u'trust admins'], - 'description': [u'Trusts administrators group'], - 'objectclass': fuzzy_set_ci(objectclasses.group), - 'ipauniqueid': [fuzzy_uuid], - }, - ], - ), - ), - - dict( - desc='Search for non-POSIX groups with criteria filter', - command=('group_find', [u'users'], dict(nonposix=True, all=True)), - expected=dict( - summary=u'1 group matched', - count=1, - truncated=False, - result=[ - { - 'dn': get_group_dn('ipausers'), - 'cn': [u'ipausers'], - 'description': [u'Default group for all users'], - 'objectclass': fuzzy_set_ci(objectclasses.group), - 'ipauniqueid': [fuzzy_uuid], - }, - ], - ), - ), - - dict( - desc='Search for POSIX groups', - command=('group_find', [], dict(posix=True, all=True)), - expected=dict( - summary=u'4 groups matched', - count=4, - truncated=False, - result=[ - add_sid({ - 'dn': get_group_dn('admins'), - 'member_user': [u'admin'], - 'gidnumber': [fuzzy_digits], - 'cn': [u'admins'], - 'description': [u'Account administrators group'], - 'objectclass': fuzzy_set_ci(add_oc( - objectclasses.posixgroup, u'ipantgroupattrs')), - 'ipauniqueid': [fuzzy_uuid], - }), - add_sid({ - 'dn': get_group_dn('editors'), - 'gidnumber': [fuzzy_digits], - 'cn': [u'editors'], - 'description': [u'Limited admins who can edit other users'], - 'objectclass': fuzzy_set_ci(add_oc( - objectclasses.posixgroup, - u'ipantgroupattrs', - check_sidgen=True)), - 'ipauniqueid': [fuzzy_uuid], - }, check_sidgen=True), - dict( - dn=get_group_dn(group1), - cn=[group1], - description=[u'New desc 1'], - gidnumber=[fuzzy_digits], - objectclass=fuzzy_set_ci(objectclasses.posixgroup), - ipauniqueid=[fuzzy_uuid], - ), - add_sid(dict( - dn=get_group_dn(group2), - cn=[group2], - description=[u'New desc 2'], - gidnumber=[fuzzy_digits], - objectclass=fuzzy_set_ci(add_oc( - objectclasses.posixgroup, u'ipantgroupattrs')), - ipauniqueid=[fuzzy_uuid], - )), - ], - ), - ), - - - ############### - # test external SID members for group3: - dict( - desc='Create external %r' % group3, - command=( - 'group_add', [group3], dict(description=u'Test desc 3',external=True) - ), - expected=dict( - value=group3, - summary=u'Added group "testgroup3"', - result=dict( - cn=[group3], - description=[u'Test desc 3'], - objectclass=objectclasses.externalgroup, - ipauniqueid=[fuzzy_uuid], - dn=get_group_dn(group3), - ), - ), - ), - - dict( - desc='Search for external groups', - command=('group_find', [], dict(external=True, all=True)), - expected=dict( - summary=u'1 group matched', - count=1, - truncated=False, - result=[ - dict( - cn=[group3], - description=[u'Test desc 3'], - objectclass=fuzzy_set_ci(objectclasses.externalgroup), - ipauniqueid=[fuzzy_uuid], - dn=get_group_dn(group3), - ), - ], - ), - ), - - - dict( - desc='Convert posix group %r to support external membership' % (group2), - command=( - 'group_mod', [group2], dict(external=True) - ), - expected=errors.PosixGroupViolation(), - ), - - - dict( - desc='Convert external members group %r to posix' % (group3), - command=( - 'group_mod', [group3], dict(posix=True) - ), - expected=errors.ExternalGroupViolation(), - ), - - - dict( - desc='Add external member %r to %r' % (external_sid1, group3), - command=( - 'group_add_member', [group3], dict(ipaexternalmember=external_sid1) - ), - expected=lambda x, output: (type(x) == errors.ValidationError - or type(x) == errors.NotFound - or 'failed' in output), - ), - - - dict( - desc='Remove group %r with external membership' % (group3), - command=('group_del', [group3], {}), - expected=dict( - result=dict(failed=[]), - value=[group3], - summary=u'Deleted group "testgroup3"', - ), - ), - - - ############### - # member stuff: - dict( - desc='Add member %r to %r' % (group2, group1), - command=( - 'group_add_member', [group1], dict(group=group2) - ), - expected=dict( - completed=1, - failed=dict( - member=dict( - group=tuple(), - user=tuple(), - ), - ), - result={ - 'dn': get_group_dn(group1), - 'member_group': (group2,), - 'gidnumber': [fuzzy_digits], - 'cn': [group1], - 'description': [u'New desc 1'], +class TestFindGroup(XMLRPC_test): + def test_search(self, group): + """ Search for a group """ + group.ensure_exists() + group.find() + + def test_search_for_all_groups(self, group, group2): + """ Search for all groups """ + group.ensure_exists() + group2.create() + command = group.make_command('group_find') + result = command() + assert_deepequal(dict( + summary=u'6 groups matched', + count=6, + truncated=False, + result=[ + { + 'dn': get_group_dn('admins'), + 'member_user': [u'admin'], + 'gidnumber': [fuzzy_digits], + 'cn': [u'admins'], + 'description': [u'Account administrators group'], + }, + { + 'dn': get_group_dn('editors'), + 'gidnumber': [fuzzy_digits], + 'cn': [u'editors'], + 'description': + [u'Limited admins who can edit other users'], }, - ), - ), - - dict( - # FIXME: Shouldn't this raise a NotFound instead? - desc='Try to add non-existent member to %r' % group1, - command=( - 'group_add_member', [group1], dict(group=u'notfound') - ), - expected=dict( - completed=0, - failed=dict( - member=dict( - group=[(u'notfound', u'no such entry')], - user=tuple(), - ), - ), - result={ - 'dn': get_group_dn(group1), - 'member_group': (group2,), - 'gidnumber': [fuzzy_digits], - 'cn': [group1], - 'description': [u'New desc 1'], + { + 'dn': get_group_dn('ipausers'), + 'cn': [u'ipausers'], + 'description': [u'Default group for all users'], }, - ), - ), - - dict( - desc='Remove member %r from %r' % (group2, group1), - command=('group_remove_member', - [group1], dict(group=group2) - ), - expected=dict( - completed=1, - failed=dict( - member=dict( - group=tuple(), - user=tuple(), - ), - ), - result={ - 'dn': get_group_dn(group1), - 'cn': [group1], + { + 'dn': get_group_dn(group.cn), + 'cn': [group.cn], + 'description': [u'Test desc1'], 'gidnumber': [fuzzy_digits], - 'description': [u'New desc 1'], }, - ), - ), - - dict( - # FIXME: Shouldn't this raise a NotFound instead? - desc='Try to remove non-existent member from %r' % group1, - command=('group_remove_member', - [group1], dict(group=u'notfound') - ), - expected=dict( - completed=0, - failed=dict( - member=dict( - group=[(u'notfound', u'This entry is not a member')], - user=tuple(), - ), - ), - result={ - 'dn': get_group_dn(group1), - 'cn': [group1], + { + 'dn': get_group_dn(group2.cn), + 'cn': [group2.cn], + 'description': [u'Test desc2'], 'gidnumber': [fuzzy_digits], - 'description': [u'New desc 1'], }, - ), - ), - - - dict( - desc='Rename %r' % group1, - command=('group_mod', [group1], dict(setattr=u'cn=%s' % renamedgroup1)), - expected=dict( - value=group1, - result=dict( - cn=[renamedgroup1], - description=[u'New desc 1'], - gidnumber=[fuzzy_digits], - ), - summary=u'Modified group "%s"' % group1 - ) - ), - - - dict( - desc='Rename %r back' % renamedgroup1, - command=('group_mod', [renamedgroup1], dict(setattr=u'cn=%s' % group1)), - expected=dict( - value=renamedgroup1, - result=dict( - cn=[group1], - description=[u'New desc 1'], - gidnumber=[fuzzy_digits], - ), - summary=u'Modified group "%s"' % renamedgroup1 - ) - ), - - - - ################ - # delete group1: - dict( - desc='Delete %r' % group1, - command=('group_del', [group1], {}), - expected=dict( - result=dict(failed=[]), - value=[group1], - summary=u'Deleted group "testgroup1"', - ) - ), - - - dict( - desc='Try to delete non-existent %r' % group1, - command=('group_del', [group1], {}), - expected=errors.NotFound(reason=u'%s: group not found' % group1), - ), - - - dict( - desc='Try to retrieve non-existent %r' % group1, - command=('group_show', [group1], {}), - expected=errors.NotFound(reason=u'%s: group not found' % group1), - ), - - - dict( - desc='Try to update non-existent %r' % group1, - command=('group_mod', [group1], dict(description=u'Foo')), - expected=errors.NotFound(reason=u'%s: group not found' % group1), - ), - - - - ################ - # delete group2: - dict( - desc='Delete %r' % group2, - command=('group_del', [group2], {}), - expected=dict( - result=dict(failed=[]), - value=[group2], - summary=u'Deleted group "testgroup2"', - ) - ), - - - dict( - desc='Try to delete non-existent %r' % group2, - command=('group_del', [group2], {}), - expected=errors.NotFound(reason=u'%s: group not found' % group2), - ), - - - dict( - desc='Try to retrieve non-existent %r' % group2, - command=('group_show', [group2], {}), - expected=errors.NotFound(reason=u'%s: group not found' % group2), - ), - - - dict( - desc='Try to update non-existent %r' % group2, - command=('group_mod', [group2], dict(description=u'Foo')), - expected=errors.NotFound(reason=u'%s: group not found' % group2), - ), - - dict( - desc='Test an invalid group name %r' % invalidgroup1, - command=('group_add', [invalidgroup1], dict(description=u'Test')), - expected=errors.ValidationError(name='group_name', - error=u'may only include letters, numbers, _, -, . and $'), - ), - - # The assumption on these next 4 tests is that if we don't get a - # validation error then the request was processed normally. - dict( - desc='Test that validation is disabled on mods', - command=('group_mod', [invalidgroup1], {}), - expected=errors.NotFound( - reason=u'%s: group not found' % invalidgroup1), - ), - - - dict( - desc='Test that validation is disabled on deletes', - command=('group_del', [invalidgroup1], {}), - expected=errors.NotFound( - reason=u'%s: group not found' % invalidgroup1), - ), - - - dict( - desc='Test that validation is disabled on show', - command=('group_show', [invalidgroup1], {}), - expected=errors.NotFound( - reason=u'%s: group not found' % invalidgroup1), - ), - - - ##### managed entry tests - dict( - desc='Create %r' % user1, - command=( - 'user_add', [], dict(givenname=u'Test', sn=u'User1') - ), - expected=dict( - value=user1, - summary=u'Added user "%s"' % user1, - result=get_user_result(user1, u'Test', u'User1', 'add'), - ), - ), - - - dict( - desc='Verify the managed group %r was created' % user1, - command=('group_show', [user1], {}), - expected=dict( - value=user1, - summary=None, - result=dict( - cn=[user1], - description=[u'User private group for %s' % user1], - gidnumber=[fuzzy_digits], - dn=get_group_dn(user1), - ), - ), - ), - - - dict( - desc='Verify that managed group %r can be found' % user1, - command=('group_find', [], {'cn': user1, 'private': True}), - expected=dict( - count=1, - truncated=False, - result=[ - dict( - dn=get_group_dn(user1), - cn=[user1], - description=[u'User private group for %s' % user1], - gidnumber=[fuzzy_digits], - ), - ], - summary=u'1 group matched', - ), - ), - - - dict( - desc='Try to delete a managed group %r' % user1, - command=('group_del', [user1], {}), - expected=errors.ManagedGroupError(), - ), - - - dict( - desc='Detach managed group %r' % user1, - command=('group_detach', [user1], {}), - expected=dict( - result=True, - value=user1, - summary=u'Detached group "%s" from user "%s"' % (user1, user1), - ), - ), - - - dict( - desc='Now delete the unmanaged group %r' % user1, - command=('group_del', [user1], {}), - expected=dict( - result=dict(failed=[]), - value=[user1], - summary=u'Deleted group "%s"' % user1, - ) - ), - - dict( - desc='Verify that %r is really gone' % user1, - command=('group_show', [user1], {}), - expected=errors.NotFound(reason=u'%s: group not found' % user1), - ), - - dict( - desc='Delete %r' % user1, - command=('user_del', [user1], {}), - expected=dict( - result=dict(failed=[]), - summary=u'Deleted user "tuser1"', - value=[user1], - ), - ), - - dict( - desc='Create %r without User Private Group' % user1, - command=( - 'user_add', [user1], dict(givenname=u'Test', sn=u'User1', noprivate=True, gidnumber=1000) - ), - expected=dict( - value=user1, - summary=u'Added user "tuser1"', - result=get_user_result( - user1, u'Test', u'User1', 'add', - description=[], - objectclass=add_oc(objectclasses.user_base, - u'ipantuserattrs'), - gidnumber=[u'1000'], - omit=['mepmanagedentry'], - ), - ), - ), - - dict( - desc='Verify the managed group %r was not created' % user1, - command=('group_show', [user1], {}), - expected=errors.NotFound(reason=u'%s: group not found' % user1), - ), - - dict( - desc='Try to remove the admin user from the admins group', - command=('group_remove_member', [u'admins'], dict(user=[u'admin'])), - expected=errors.LastMemberError(key=u'admin', label=u'group', - container='admins'), - ), - - dict( - desc='Add %r to the admins group' % user1, - command=('group_add_member', [u'admins'], dict(user=user1)), - expected=dict( - completed=1, - failed=dict( - member=dict( - group=tuple(), - user=tuple(), - ), - ), - result={ - 'dn': get_group_dn('admins'), - 'member_user': [u'admin', user1], - 'gidnumber': [fuzzy_digits], - 'cn': [u'admins'], - 'description': [u'Account administrators group'], + { + 'dn': get_group_dn('trust admins'), + 'member_user': [u'admin'], + 'cn': [u'trust admins'], + 'description': [u'Trusts administrators group'], + }, + ]), result) + + def test_search_for_all_posix(self, group, group2): + """ Search for all posix groups """ + command = group.make_command( + 'group_find', **dict(posix=True, all=True) + ) + result = command() + assert_deepequal(dict( + summary=u'4 groups matched', + count=4, + truncated=False, + result=[ + { + 'dn': get_group_dn('admins'), + 'member_user': [u'admin'], + 'gidnumber': [fuzzy_digits], + 'cn': [u'admins'], + 'description': [u'Account administrators group'], + 'objectclass': fuzzy_set_ci(add_oc( + objectclasses.posixgroup, u'ipantgroupattrs')), + 'ipauniqueid': [fuzzy_uuid], + }, + { + 'dn': get_group_dn('editors'), + 'gidnumber': [fuzzy_digits], + 'cn': [u'editors'], + 'description': + [u'Limited admins who can edit other users'], + 'objectclass': fuzzy_set_ci(add_oc( + objectclasses.posixgroup, u'ipantgroupattrs')), + 'ipauniqueid': [fuzzy_uuid], }, - ), - ), - - dict( - desc='Try to remove admin and %r from the admins group' % user1, - command=('group_remove_member', [u'admins'], - dict(user=[u'admin', user1])), - expected=errors.LastMemberError(key=u'admin', label=u'group', - container='admins'), - ), - - dict( - desc='Try to delete the admins group', - command=('group_del', [u'admins'], {}), - expected=errors.ProtectedEntryError(label=u'group', - key='admins', reason='privileged group'), - ), - - - dict( - desc='Try to rename the admins group', - command=('group_mod', [u'admins'], dict(rename=u'loosers')), - expected=errors.ProtectedEntryError(label=u'group', - key='admins', reason='Cannot be renamed'), - ), - - dict( - desc='Try to rename the admins group via setattr', - command=('group_mod', [u'admins'], {'setattr': u'cn=loosers'}), - expected=errors.ProtectedEntryError(label=u'group', - key='admins', reason='Cannot be renamed'), - ), - - dict( - desc='Try to modify the admins group to support external membership', - command=('group_mod', [u'admins'], dict(external=True)), - expected=errors.ProtectedEntryError(label=u'group', - key='admins', reason='Cannot support external non-IPA members'), - ), - - dict( - desc='Try to delete the trust admins group', - command=('group_del', [u'trust admins'], {}), - expected=errors.ProtectedEntryError(label=u'group', - key='trust admins', reason='privileged group'), - ), - - dict( - desc='Try to rename the trust admins group', - command=('group_mod', [u'trust admins'], dict(rename=u'loosers')), - expected=errors.ProtectedEntryError(label=u'group', - key='trust admins', reason='Cannot be renamed'), - ), - - dict( - desc='Try to rename the trust admins group via setattr', - command=('group_mod', [u'trust admins'], {'setattr': u'cn=loosers'}), - expected=errors.ProtectedEntryError(label=u'group', - key='trust admins', reason='Cannot be renamed'), - ), - - - dict( - desc='Try to modify the trust admins group to support external membership', - command=('group_mod', [u'trust admins'], dict(external=True)), - expected=errors.ProtectedEntryError(label=u'group', - key='trust admins', reason='Cannot support external non-IPA members'), - ), - - dict( - desc='Delete %r' % user1, - command=('user_del', [user1], {}), - expected=dict( - result=dict(failed=[]), - summary=u'Deleted user "%s"' % user1, - value=[user1], - ), - ), - ] + { + 'dn': get_group_dn(group.cn), + 'cn': [group.cn], + 'description': [u'Test desc1'], + 'gidnumber': [fuzzy_digits], + 'objectclass': fuzzy_set_ci(add_oc( + objectclasses.posixgroup, u'ipantgroupattrs')), + 'ipauniqueid': [fuzzy_uuid], + }, + { + 'dn': get_group_dn(group2.cn), + 'cn': [group2.cn], + 'description': [u'Test desc2'], + 'gidnumber': [fuzzy_digits], + 'objectclass': fuzzy_set_ci(add_oc( + objectclasses.posixgroup, u'ipantgroupattrs')), + 'ipauniqueid': [fuzzy_uuid], + }, + ]), result) @pytest.mark.tier1 -class test_group_remove_group_from_protected_group(Declarative): - cleanup_commands = [ - ('group_del', [group1], {}), - ] - tests = [ - # Test scenario from ticket #4448 - # https://fedorahosted.org/freeipa/ticket/4448 - dict( - desc='Add group %s' % group1, - command=('group_add', [group1], dict(description=u'Test desc 1')), - expected=dict( - value=group1, - summary=u'Added group "%s"' % group1, - result=dict( - cn=[group1], - description=[u'Test desc 1'], - objectclass=objectclasses.posixgroup, - gidnumber=[fuzzy_digits], - ipauniqueid=[fuzzy_uuid], - dn=get_group_dn(group1), - ), - ), - ), - - dict( - desc='Add %s group to admins group' % group1, - command=('group_add_member', [u'admins'], dict(group=group1)), - expected=dict( - completed=1, - failed=dict( - member=dict( - group=tuple(), - user=tuple(), - ), - ), - result=dict( - dn=get_group_dn('admins'), - member_user=[u'admin'], - member_group=[group1], - gidnumber=[fuzzy_digits], - cn=[u'admins'], - description=[u'Account administrators group'], - ), - ), - ), - - dict( - desc='Remove %s group from admins group' % group1, - command=('group_remove_member', [u'admins'], dict(group=group1)), - expected=dict( - completed=1, - failed=dict( - member=dict( - group=tuple(), - user=tuple(), - ), - ), - result=dict( - dn=get_group_dn(u'admins'), - cn=[u'admins'], - gidnumber=[fuzzy_digits], - member_user=[u'admin'], - description=[u'Account administrators group'], - ), - ), - ), - ] +class TestNonexistentGroup(XMLRPC_test): + def test_retrieve_nonexistent(self, group): + """ Try to retrieve a non-existent group """ + group.ensure_missing() + command = group.make_retrieve_command() + with raises_exact(errors.NotFound( + reason=u'%s: group not found' % group.cn)): + command() + + def test_update_nonexistent(self, group): + """ Try to update a non-existent group """ + group.ensure_missing() + command = group.make_update_command( + updates=dict(description=u'hey')) + with raises_exact(errors.NotFound( + reason=u'%s: group not found' % group.cn)): + command() + + def test_delete_nonexistent(self, group): + """ Try to delete a non-existent user """ + group.ensure_missing() + command = group.make_delete_command() + with raises_exact(errors.NotFound( + reason=u'%s: group not found' % group.cn)): + command() + + def test_rename_nonexistent(self, group): + """ Try to rename a non-existent user """ + group.ensure_missing() + command = group.make_update_command( + updates=dict(setattr=u'cn=%s' % renamedgroup1)) + with raises_exact(errors.NotFound( + reason=u'%s: group not found' % group.cn)): + command() @pytest.mark.tier1 -class test_group_full_set_of_objectclass_not_available_post_detach(Declarative): - # https://fedorahosted.org/freeipa/ticket/4909#comment:1 - cleanup_commands = [ - ('group_del', [user1], {}), - ('user_del', [user1], {}), - ] - - tests = [ - dict( - desc='Create %r' % user1, - command=( - 'user_add', [], dict(givenname=u'Test', sn=u'User1') - ), - expected=dict( - value=user1, - summary=u'Added user "%s"' % user1, - result=get_user_result(user1, u'Test', u'User1', 'add'), - ), - ), - - dict( - desc='Detach managed group %r' % user1, - command=('group_detach', [user1], {}), - expected=dict( - result=True, - value=user1, - summary=u'Detached group "%s" from user "%s"' % (user1, user1), - ), - ), - - dict( - desc='Show group - check objectclass', - command=('group_show', [user1], dict(all=True)), - expected=dict( - value=user1, - result={ - 'cn':[user1], - 'description': [u'User private group for tuser1'], - 'gidnumber': [fuzzy_digits], - 'dn': get_group_dn('tuser1'), +class TestNonposixGroup(XMLRPC_test): + def test_create_nonposix(self, group): + """ Create a non-posix group """ + group.track_create() + command = group.make_create_command(**dict(nonposix=True)) + result = command() + + del group.attrs['gidnumber'] + group.attrs.update(objectclass=objectclasses.group) + group.check_create(result) + + def test_create_duplicate_to_nonposix(self, group): + """ Try to create a duplicate non-posix group """ + group.ensure_exists() + command = group.make_create_command() + + with raises_exact(errors.DuplicateEntry( + message=u'group with name "%s" already exists' % group.cn)): + command() + + def test_retrieve_nonposix(self, group): + """ Retrieve a non-posix group """ + group.retrieve() + + def test_update_nonposix(self, group): + """ Update a non-posix group with new description + and perform retrieve command to verify the update """ + group.update(dict(description=u'New desc')) + group.retrieve() + + def test_search_for_all_nonposix(self, group): + """ Perform a search for all non-posix groups """ + command = group.make_command( + 'group_find', **dict(nonposix=True, all=True) + ) + result = command() + assert_deepequal(dict( + summary=u'3 groups matched', + count=3, + truncated=False, + result=[ + { + 'dn': get_group_dn('ipausers'), + 'cn': [u'ipausers'], + 'description': [u'Default group for all users'], + 'objectclass': fuzzy_set_ci(objectclasses.group), + 'ipauniqueid': [fuzzy_uuid], + }, + { + 'dn': get_group_dn(group.cn), + 'cn': [group.cn], + 'description': [u'New desc'], + 'objectclass': fuzzy_set_ci(objectclasses.group), + 'ipauniqueid': [fuzzy_uuid], + }, + { + 'dn': get_group_dn('trust admins'), + 'member_user': [u'admin'], + 'cn': [u'trust admins'], + 'description': [u'Trusts administrators group'], + 'objectclass': fuzzy_set_ci(objectclasses.group), 'ipauniqueid': [fuzzy_uuid], - 'objectclass': objectclasses.posixgroup, }, - summary=None, - ), - ), - - dict( - desc='Add member back to the detached group', - command=('group_add_member', [user1], dict(user=user1)), - expected=dict( - completed=1, - failed=dict( - member=dict( - group=tuple(), - user=tuple(), - ), - ), - result={ - 'dn': get_group_dn('tuser1'), - 'member_user': [user1], - 'gidnumber': [fuzzy_digits], - 'cn': [user1], - 'description': [u'User private group for tuser1'], + ], + ), result) + + def test_upgrade_nonposix_to_posix(self, group): + """ Update non-posix group to promote it to posix group """ + group.attrs.update(gidnumber=[fuzzy_digits]) + group.update(dict(posix=True), dict(posix=None)) + group.retrieve() + + def test_search_for_all_nonposix_with_criteria(self, group): + """ Search for all non-posix groups with additional + criteria filter """ + command = group.make_command( + 'group_find', *[u'users'], **dict(nonposix=True, all=True) + ) + result = command() + assert_deepequal(dict( + summary=u'1 group matched', + count=1, + truncated=False, + result=[ + { + 'dn': get_group_dn('ipausers'), + 'cn': [u'ipausers'], + 'description': [u'Default group for all users'], + 'objectclass': fuzzy_set_ci(objectclasses.group), + 'ipauniqueid': [fuzzy_uuid], }, - ), - ), - ] + ], + ), result) + + +@pytest.mark.tier1 +class TestExternalGroup(XMLRPC_test): + def test_create_external(self, group): + """ Create a non-posix group """ + group.track_create() + del group.attrs['gidnumber'] + group.attrs.update(objectclass=objectclasses.externalgroup) + command = group.make_create_command(**dict(external=True)) + result = command() + group.check_create(result) + + def test_search_for_external(self, group): + """ Search for all external groups """ + command = group.make_command( + 'group_find', **dict(external=True, all=True) + ) + result = command() + group.check_find(result, all=True) + + def test_convert_external_to_posix(self, group): + """ Try to convert an external group to posix """ + command = group.make_update_command(dict(posix=True)) + with raises_exact(errors.ExternalGroupViolation( + reason=u'This group cannot be posix because it is external')): + command() + + def test_add_external_member_to_external(self, group): + """ Try to add an invalid external member to an external + group and check that proper exceptions are raised """ + # When adding external SID member to a group we can't test + # it fully due to possibly missing Samba 4 python bindings + # and/or not configured AD trusts. Thus, we'll use incorrect + # SID value to merely test that proper exceptions are raised + command = group.make_command('group_add_member', *[group.cn], + **dict(ipaexternalmember=external_sid1)) + try: + command() + except Exception as ex: + if type(ex) == errors.ValidationError: + pass + elif type(ex) == errors.NotFound: + pass + elif 'failed' in str(ex): + pass + else: + raise ex + + def test_delete_external_group(self, group): + group.delete() + + +@pytest.mark.tier1 +class TestGroupMember(XMLRPC_test): + def test_add_nonexistent_member(self, group): + """ Try to add non-existent member to a group """ + group.create() + command = group.make_add_member_command(dict(group=notagroup)) + result = command() + group.check_add_member_negative(result, dict(group=notagroup)) + + def test_remove_nonexistent_member(self, group): + """ Try to remove non-existent member from a group """ + group.ensure_exists() + command = group.make_remove_member_command(dict(group=notagroup)) + result = command() + group.check_remove_member_negative(result, dict(group=notagroup)) + + def test_add_member(self, group, group2): + """ Add member group to a group """ + group.ensure_exists() + group2.ensure_exists() + group.add_member(dict(group=group2.cn)) + + def test_remove_member(self, group, group2): + """ Remove a group member """ + group.ensure_exists() + group2.ensure_exists() + group.remove_member(dict(group=group2.cn)) + + def test_add_and_remove_group_from_admins(self, group, admins): + """ Add group to protected admins group and then remove it """ + # Test scenario from ticket #4448 + # https://fedorahosted.org/freeipa/ticket/4448 + group.ensure_exists() + admins.add_member(dict(group=group.cn)) + admins.remove_member(dict(group=group.cn)) + + +@pytest.mark.tier1 +class TestValidation(XMLRPC_test): + # The assumption for this class of tests is that if we don't + # get a validation error then the request was processed normally. + + def test_validation_disabled_on_delete(self, group): + """ Test that validation is disabled on group deletes """ + command = group.make_command('group_del', invalidgroup1) + with raises_exact(errors.NotFound( + reason=u'%s: group not found' % invalidgroup1)): + command() + + def test_validation_disabled_on_show(self, group): + """ Test that validation is disabled on group retrieves """ + command = group.make_command('group_show', invalidgroup1) + with raises_exact(errors.NotFound( + reason=u'%s: group not found' % invalidgroup1)): + command() + + def test_validation_disabled_on_mod(self, group): + """ Test that validation is disabled on group mods """ + command = group.make_command('group_mod', invalidgroup1) + with raises_exact(errors.NotFound( + reason=u'%s: group not found' % invalidgroup1)): + command() + + +@pytest.mark.tier1 +class TestManagedGroups(XMLRPC_test): + def test_verify_managed_created(self, managed_group): + """ Verify that managed group is created with new user """ + managed_group.retrieve() + + def test_verify_managed_findable(self, managed_group): + """ Verify that managed group can be found """ + command = managed_group.make_find_command( + **dict(cn=managed_group.cn, private=True) + ) + result = command() + managed_group.check_find(result) + + def test_delete_managed(self, managed_group): + """ Try to delete managed group """ + command = managed_group.make_delete_command() + with raises_exact(errors.ManagedGroupError()): + command() + + def test_detach_managed(self, managed_group): + """ Detach managed group from a user """ + command = managed_group.make_detach_command() + result = command() + managed_group.check_detach(result) + + def test_delete_detached_managed(self, managed_group, user): + """ Delete a previously managed group that is now detached + and verify it's really gone """ + managed_group.delete() + command = managed_group.make_retrieve_command() + with raises_exact(errors.NotFound( + reason=u'%s: group not found' % managed_group.cn)): + command() + user.ensure_missing() + + def test_verify_managed_missing_for_user_without_upg(self, user_npg2): + """ Create a user without user private group and + verify private group wasn't created """ + user_npg2.attrs.update(memberof_group=[u'ipausers']) + command = user_npg2.make_create_command() + result = command() + user_npg2.check_create(result, [u'description', u'memberof_group']) + command = user_npg2.make_command('group_show', *[user_npg2.uid]) + with raises_exact(errors.NotFound( + reason=u'%s: group not found' % user_npg2.uid)): + command() + + +@pytest.mark.tier1 +class TestManagedGroupObjectclasses(XMLRPC_test): + def test_check_objectclasses_after_detach(self, user, managed_group): + """ Check objectclasses after user was detached from managed group """ + # https://fedorahosted.org/freeipa/ticket/4909#comment:1 + user.create() + user.run_command('group_detach', *[user.uid]) + managed_group.retrieve(all=True) + managed_group.add_member(dict(user=user.uid)) + managed_group.ensure_missing() + user.ensure_missing() + + +@pytest.mark.tier1 +class TestAdminGroup(XMLRPC_test): + def test_remove_admin_from_admins(self, admins): + """ Remove the original admin from admins group """ + command = admins.make_remove_member_command( + dict(user=u'admin') + ) + with raises_exact(errors.LastMemberError( + key=u'admin', label=u'group', container=admins.cn)): + command() + + def test_add_another_admin(self, admins, user): + """ Add second member to the admins group """ + user.ensure_exists() + admins.add_member(dict(user=user.uid)) + + def test_remove_all_admins_from_admins(self, admins, user): + """ Try to remove both original and our admin from admins group """ + command = admins.make_remove_member_command( + dict(user=[u'admin', user.uid]) + ) + with raises_exact(errors.LastMemberError( + key=u'admin', label=u'group', container=admins.cn)): + command() + + def test_delete_admins(self, admins): + """ Try to delete the protected admins group """ + command = admins.make_delete_command() + with raises_exact(errors.ProtectedEntryError(label=u'group', + key=admins.cn, reason='privileged group')): + command() + + def test_rename_admins(self, admins): + """ Try to rename the protected admins group """ + command = admins.make_command('group_mod', *[admins.cn], + **dict(rename=renamedgroup1)) + with raises_exact(errors.ProtectedEntryError(label=u'group', + key=admins.cn, reason='Cannot be renamed')): + command() + + def test_rename_admins_using_setattr(self, admins): + """ Try to rename the protected admins group using setattr """ + command = admins.make_command('group_mod', *[admins.cn], + **dict(setattr=u'cn=%s' % renamedgroup1)) + with raises_exact(errors.ProtectedEntryError(label=u'group', + key=admins.cn, reason='Cannot be renamed')): + command() + + def test_update_admins_to_support_external_membership(self, admins): + """ Try to modify the admins group to support external membership """ + command = admins.make_command('group_mod', *[admins.cn], + **dict(external=True)) + with raises_exact(errors.ProtectedEntryError(label=u'group', + key=admins.cn, + reason='Cannot support external non-IPA members')): + command() + + +@pytest.mark.tier1 +class TestTrustAdminGroup(XMLRPC_test): + def test_delete_trust_admins(self, trustadmins): + """ Try to delete the protected 'trust admins' group """ + command = trustadmins.make_delete_command() + with raises_exact(errors.ProtectedEntryError(label=u'group', + key=trustadmins.cn, reason='privileged group')): + command() + + def test_rename_trust_admins(self, trustadmins): + """ Try to rename the protected 'trust admins' group """ + command = trustadmins.make_command('group_mod', *[trustadmins.cn], + **dict(rename=renamedgroup1)) + with raises_exact(errors.ProtectedEntryError(label=u'group', + key=trustadmins.cn, reason='Cannot be renamed')): + command() + + def test_rename_trust_admins_using_setattr(self, trustadmins): + """ Try to rename the protected 'trust admins' group using setattr """ + command = trustadmins.make_command( + 'group_mod', *[trustadmins.cn], + **dict(setattr=u'cn=%s' % renamedgroup1) + ) + with raises_exact(errors.ProtectedEntryError(label=u'group', + key=trustadmins.cn, reason='Cannot be renamed')): + command() + + def test_update_trust_admins_to_support_external_membership( + self, trustadmins + ): + """ Try to modify the 'trust admins' group to + support external membership """ + command = trustadmins.make_command( + 'group_mod', *[trustadmins.cn], + **dict(external=True) + ) + with raises_exact(errors.ProtectedEntryError(label=u'group', + key=trustadmins.cn, + reason='Cannot support external non-IPA members')): + command() diff --git a/ipatests/test_xmlrpc/test_stageuser_plugin.py b/ipatests/test_xmlrpc/test_stageuser_plugin.py index b6744eb8e..689682c9d 100644 --- a/ipatests/test_xmlrpc/test_stageuser_plugin.py +++ b/ipatests/test_xmlrpc/test_stageuser_plugin.py @@ -634,9 +634,7 @@ class TestGroups(XMLRPC_test): def test_remove_preserved_from_group(self, user, group): user.ensure_exists() group.ensure_exists() - command = group.make_add_member_command(options={u'user': user.uid}) - result = command() - group.check_add_member(result) + command = group.add_member(options={u'user': user.uid}) command = group.make_retrieve_command() result = command() diff --git a/ipatests/test_xmlrpc/tracker/group_plugin.py b/ipatests/test_xmlrpc/tracker/group_plugin.py index c47ce8ecf..9f399cad5 100644 --- a/ipatests/test_xmlrpc/tracker/group_plugin.py +++ b/ipatests/test_xmlrpc/tracker/group_plugin.py @@ -12,7 +12,7 @@ from ipatests.util import assert_deepequal, get_group_dn class GroupTracker(Tracker): """ Class for host plugin like tests """ retrieve_keys = {u'dn', u'cn', u'gidnumber', u'member_user', - u'member_group'} + u'member_group', u'description'} retrieve_all_keys = retrieve_keys | {u'ipauniqueid', u'objectclass'} create_keys = retrieve_all_keys @@ -20,16 +20,19 @@ class GroupTracker(Tracker): add_member_keys = retrieve_keys | {u'description'} - def __init__(self, name): + def __init__(self, name, description=u'Group desc'): super(GroupTracker, self).__init__(default_version=None) self.cn = name - self.dn = get_group_dn(name) + self.description = description + self.dn = get_group_dn(self.cn) def make_create_command(self, nonposix=False, external=False, - force=True): + force=True, *args, **kwargs): """ Make function that creates a group using 'group-add' """ return self.make_command('group_add', self.cn, - nonposix=nonposix, external=external) + description=self.description, + nonposix=nonposix, external=external, + *args, **kwargs) def make_delete_command(self): """ Make function that deletes a group using 'group-del' """ @@ -48,23 +51,12 @@ class GroupTracker(Tracker): return self.make_command('group_mod', self.cn, **updates) def make_add_member_command(self, options={}): - """ Make function that adds a member to a group - Attention: only works for one user OR group! """ - if u'user' in options: - self.attrs[u'member_user'] = [options[u'user']] - elif u'group' in options: - self.attrs[u'member_group'] = [options[u'group']] + """ Make function that adds a member to a group """ self.adds = options - return self.make_command('group_add_member', self.cn, **options) def make_remove_member_command(self, options={}): - """ Make function that removes a member from a group - Attention: only works for one user OR group! """ - if u'user' in options: - del self.attrs[u'member_user'] - elif u'group' in options: - del self.attrs[u'member_group'] + """ Make function that removes a member from a group """ return self.make_command('group_remove_member', self.cn, **options) def make_detach_command(self): @@ -78,12 +70,85 @@ class GroupTracker(Tracker): self.attrs = dict( dn=get_group_dn(self.cn), cn=[self.cn], + description=[self.description], gidnumber=[fuzzy_digits], ipauniqueid=[fuzzy_uuid], objectclass=objectclasses.posixgroup, ) self.exists = True + def update(self, updates, expected_updates=None): + """Helper function to update the group and check the result + + Overriding Tracker method for setting self.attrs correctly; + * most attributes stores its value in list + * the rest can be overridden by expected_updates + * allow deleting parametrs if update value is None + """ + if expected_updates is None: + expected_updates = {} + + self.ensure_exists() + command = self.make_update_command(updates) + result = command() + + for key, value in updates.items(): + if value is None: + del self.attrs[key] + else: + self.attrs[key] = [value] + for key, value in expected_updates.items(): + if value is None: + del self.attrs[key] + else: + self.attrs[key] = value + + self.check_update( + result, + extra_keys=set(updates.keys()) | set(expected_updates.keys()) + ) + + def add_member(self, options): + """ Add a member (group OR user) and performs check """ + if u'user' in options: + try: + self.attrs[u'member_user'] =\ + self.attrs[u'member_user'] + [options[u'user']] + except KeyError as ex: + self.attrs[u'member_user'] = [options[u'user']] + elif u'group' in options: + try: + self.attrs[u'member_group'] =\ + self.attrs[u'member_group'] + [options[u'group']] + except KeyError as ex: + self.attrs[u'member_group'] = [options[u'group']] + + command = self.make_add_member_command(options) + result = command() + self.check_add_member(result) + + def remove_member(self, options): + """ Remove a member (group OR user) and performs check """ + if u'user' in options: + self.attrs[u'member_user'].remove(options[u'user']) + elif u'group' in options: + self.attrs[u'member_group'].remove(options[u'group']) + + try: + if not self.attrs[u'member_user']: + del self.attrs[u'member_user'] + except KeyError as ex: + pass + try: + if not self.attrs[u'member_group']: + del self.attrs[u'member_group'] + except KeyError as ex: + pass + + command = self.make_remove_member_command(options) + result = command() + self.check_remove_member(result) + def check_create(self, result): """ Checks 'group_add' command result """ assert_deepequal(dict( @@ -143,35 +208,48 @@ class GroupTracker(Tracker): result=self.filter_attrs(self.add_member_keys) ), result) - def check_add_member_negative(self, result): - """ Checks 'group_add_member' command result when expected result - is failure of the operation""" - if u'member_user' in self.attrs: - del self.attrs[u'member_user'] - elif u'member_group' in self.attrs: - del self.attrs[u'member_group'] + def check_add_member_negative(self, result, options={}): + """ Checks 'group_add_member' command result + when expected result is failure of the operation""" + expected = dict( + completed=0, + failed={u'member': {u'group': (), u'user': ()}}, + result=self.filter_attrs(self.add_member_keys) + ) + if not options: + try: + options = self.adds + except NameError: + pass + if u'user' in options: + expected[u'failed'][u'member'][u'user'] = [( + options[u'user'], u'no such entry')] + elif u'group' in options: + expected[u'failed'][u'member'][u'group'] = [( + options[u'group'], u'no such entry')] + + assert_deepequal(expected, result) + def check_remove_member_negative(self, result, options): + """ Checks 'group_remove_member' command result + when expected result is failure of the operation""" expected = dict( completed=0, failed={u'member': {u'group': (), u'user': ()}}, result=self.filter_attrs(self.add_member_keys) ) - if u'user' in self.adds: + if u'user' in options: expected[u'failed'][u'member'][u'user'] = [( - self.adds[u'user'], u'no such entry')] - elif u'group' in self.adds: + options[u'user'], u'This entry is not a member')] + elif u'group' in options: expected[u'failed'][u'member'][u'group'] = [( - self.adds[u'group'], u'no such entry')] + options[u'group'], u'This entry is not a member')] assert_deepequal(expected, result) def check_remove_member(self, result): """ Checks 'group_remove_member' command result """ - assert_deepequal(dict( - completed=1, - failed={u'member': {u'group': (), u'user': ()}}, - result=self.filter_attrs(self.add_member_keys) - ), result) + self.check_add_member(result) def check_detach(self, result): """ Checks 'group_detach' command result """ @@ -181,16 +259,3 @@ class GroupTracker(Tracker): self.cn, self.cn), result=True ), result) - - def make_fixture_detach(self, request): - """Make a pytest fixture for this tracker - - The fixture ensures the plugin entry does not exist before - and after the tests that use itself. - """ - def cleanup(): - pass - - request.addfinalizer(cleanup) - - return self |