On Mon, 7 Dec 2015 17:49:18 +0100 Milan Kubík <mku...@redhat.com> wrote:
> On 12/03/2015 08:15 PM, Filip Škola wrote: > > On Mon, 30 Nov 2015 17:18:30 +0100 > > Milan Kubík <mku...@redhat.com> wrote: > > > >> On 11/23/2015 04:42 PM, Filip Škola wrote: > >>> Sending updated patch. > >>> > >>> F. > >>> > >>> On Mon, 23 Nov 2015 14:59:34 +0100 > >>> Filip Škola <fsk...@redhat.com> wrote: > >>> > >>>> Found couple of issues (broke some dependencies). > >>>> > >>>> NACK > >>>> > >>>> F. > >>>> > >>>> On Fri, 20 Nov 2015 13:56:36 +0100 > >>>> Filip Škola <fsk...@redhat.com> wrote: > >>>> > >>>>> Another one. > >>>>> > >>>>> F. > >>> > >> Hi, the tests look good. Few remarks, though. > >> > >> 1. Please, use the shortes copyright notice in new modules. > >> > >> # > >> # Copyright (C) 2015 FreeIPA Contributors see COPYING for > >> license # > >> > >> 2. The tests `test_group_remove_group_from_protected_group` and > >> `test_group_full_set_of_objectclass_not_available_post_detach` > >> were not ported. Please, include them in the patch. > >> > >> Also, for less hassle, please rebase your patches on top of > >> freeipa-mkubik-0025-3-Separated-Tracker-implementations-into-standalone-pa.patch > >> Which changes the location of tracker implementations and prevents > >> circular imports. > >> > >> Thanks. > >> > > > > > > Hi, > > > > these cases are there, in corresponding classes. They are marked > > with the original comments. (However I can move them to separate > > class if desirable.) > > > > The copyright notice is changed. Also included a few changes in the > > test with user without private group. > > > > Filip > NACK > > linter: > ************* Module tracker.group_plugin > ipatests/test_xmlrpc/tracker/group_plugin.py:257: > [E0102(function-redefined), GroupTracker.check_remove_member] method > already defined line 253) > > Probably a leftover after the rebase made on top of my patch. Please > fix it. You can check youch changes by make-lint script before > sending them. > > Thanks > Hi, I learned to use make-lint! Thanks, F.
>From 2e231e285215818bbe1e06aeba573d43c86fab8b Mon Sep 17 00:00:00 2001 From: Filip Skola <fsk...@redhat.com> Date: Mon, 9 Nov 2015 16:48:55 +0100 Subject: [PATCH] Refactor test_group_plugin, use GroupTracker for tests --- ipatests/test_xmlrpc/test_group_plugin.py | 1728 +++++++++---------------- ipatests/test_xmlrpc/test_stageuser_plugin.py | 4 +- ipatests/test_xmlrpc/tracker/group_plugin.py | 149 ++- 3 files changed, 736 insertions(+), 1145 deletions(-) diff --git a/ipatests/test_xmlrpc/test_group_plugin.py b/ipatests/test_xmlrpc/test_group_plugin.py index f2bd0f4b9c8d517500b63cf49a8a7bc7c29aab6e..1ac278c7e224b8dd8793dc56c299dcae88aa78a3 100644 --- a/ipatests/test_xmlrpc/test_group_plugin.py +++ b/ipatests/test_xmlrpc/test_group_plugin.py @@ -1,6 +1,7 @@ # Authors: # Rob Crittenden <rcrit...@redhat.com> # Pavel Zuna <pz...@redhat.com> +# Filip Skola <fsk...@redhat.com> # # Copyright (C) 2008 Red Hat # see file 'COPYING' for use and warranty information @@ -26,1137 +27,648 @@ import pytest from ipalib import api, 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, XMLRPC_test, raises_exact) +from ipatests.test_xmlrpc.xmlrpc_test import ( + fuzzy_digits, fuzzy_uuid, fuzzy_set_ci, add_sid, add_oc, + XMLRPC_test, raises_exact +) from ipapython.dn import DN -from ipatests.test_xmlrpc.test_user_plugin import get_user_result +from ipatests.test_xmlrpc.tracker.group_plugin import GroupTracker from ipatests.test_xmlrpc.tracker.user_plugin import UserTracker -from ipatests.util import assert_deepequal +from ipatests.test_xmlrpc.test_user_plugin import user, user_npg2 +from ipatests.util import assert_deepequal, get_group_dn -group1 = u'testgroup1' -group2 = u'testgroup2' -group3 = u'testgroup3' -renamedgroup1 = u'testgroup' -user1 = u'tuser1' +notagroup = u'notagroup' +renamedgroup1 = u'renamedgroup' +invalidgroup1 = u'+tgroup1' +external_sid1 = u'S-1-1-123456-789-1' -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' +@pytest.fixture(scope='class') +def group(request): + tracker = GroupTracker(name=u'testgroup1', description=u'Test desc1') + return tracker.make_fixture(request) -def get_group_dn(cn): - return DN(('cn', cn), api.env.container_group, api.env.basedn) + +@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 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 @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 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 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'], + }, + { + 'dn': get_group_dn('ipausers'), + 'cn': [u'ipausers'], + 'description': [u'Default group for all users'], + }, + { + 'dn': get_group_dn(group.cn), + 'cn': [group.cn], + 'description': [u'Test desc1'], + 'gidnumber': [fuzzy_digits], + }, + { + 'dn': get_group_dn(group2.cn), + 'cn': [group2.cn], + 'description': [u'Test desc2'], + 'gidnumber': [fuzzy_digits], }, - ), - ), - - 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('trust admins'), + 'member_user': [u'admin'], + 'cn': [u'trust admins'], + 'description': [u'Trusts administrators group'], }, - ), - ), - - 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], + ]), 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], - 'description': [u'New desc 1'], + 'cn': [u'admins'], + 'description': [u'Account administrators group'], + 'objectclass': fuzzy_set_ci(add_oc( + objectclasses.posixgroup, u'ipantgroupattrs')), + 'ipauniqueid': [fuzzy_uuid], }, - ), - ), - - 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('editors'), 'gidnumber': [fuzzy_digits], - 'description': [u'New desc 1'], + '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='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(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], }, - ), - ), - - 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(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 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 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], + }, + ], + ), 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 test_group_remove_group_from_protected_group(Declarative): - cleanup_commands = [ - ('group_del', [group1], {}), - ] - tests = [ +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 - 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'], - ), - ), - ), - ] + group.ensure_exists() + admins.add_member(dict(group=group.cn)) + admins.remove_member(dict(group=group.cn)) @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'), - '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'], - }, - ), - ), - ] +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 4eb968451f926ca0ee8fa5aeae1a96770f56eb45..bfe89c856deb7798a893c3086a32d3fe11acc80b 100644 --- a/ipatests/test_xmlrpc/test_stageuser_plugin.py +++ b/ipatests/test_xmlrpc/test_stageuser_plugin.py @@ -633,9 +633,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 c47ce8ecf185f6491847b8fd7894abc249381004..cadc2706bd7a37000eb3f320bf63dcc86a6dc0d9 100644 --- a/ipatests/test_xmlrpc/tracker/group_plugin.py +++ b/ipatests/test_xmlrpc/tracker/group_plugin.py @@ -8,11 +8,14 @@ from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_digits, fuzzy_uuid from ipatests.test_xmlrpc.tracker.base import Tracker from ipatests.util import assert_deepequal, get_group_dn +from ipalib import api +from ipapython.dn import 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 +23,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 +54,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 +73,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 this user 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.iteritems(): + if value is None: + del self.attrs[key] + else: + self.attrs[key] = [value] + for key, value in expected_updates.iteritems(): + 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 +211,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 """ -- 2.4.6
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code