Hi,

fixed.

F.

On Tue, 10 Nov 2015 10:52:45 +0100
Milan Kubík <mku...@redhat.com> wrote:

> On 11/09/2015 04:35 PM, Filip Škola wrote:
> > Another patch was applied in the meantime.
> >
> > Attaching an updated version.
> >
> > F.
> >
> > On Mon, 9 Nov 2015 13:35:02 +0100
> > Milan Kubík <mku...@redhat.com> wrote:
> >
> >> On 11/06/2015 11:32 AM, Filip Škola wrote:
> >>>
> >> Hi,
> >> the patch doesn't apply.
> >>
> Please fix this.
> 
>      ipatests/test_xmlrpc/test_user_plugin.py:1419: 
> [E0602(undefined-variable), 
> TestDeniedBindWithExpiredPrincipal.teardown_class] Undefined variable 
> 'user1')
> 
> Also, use the version numbers for your changed patches.
> 

>From cdaa729b2bf3694f157e7f3fe62dd782e1a03334 Mon Sep 17 00:00:00 2001
From: Filip Skola <fsk...@redhat.com>
Date: Fri, 6 Nov 2015 10:57:37 +0100
Subject: [PATCH] Refactor test_user_plugin, use UserTracker for tests

---
 ipatests/test_xmlrpc/test_user_plugin.py | 2809 +++++++++++++-----------------
 1 file changed, 1195 insertions(+), 1614 deletions(-)

diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py
index 81185e449acaa127aa9429fff9587d39a2be81e6..2d63e1636abd6bb55d541df354d039404c6475e8 100644
--- a/ipatests/test_xmlrpc/test_user_plugin.py
+++ b/ipatests/test_xmlrpc/test_user_plugin.py
@@ -2,6 +2,7 @@
 #   Rob Crittenden <rcrit...@redhat.com>
 #   Pavel Zuna <pz...@redhat.com>
 #   Jason Gerard DeRose <jder...@redhat.com>
+#   Filip Skola <fsk...@redhat.com>
 #
 # Copyright (C) 2008, 2009  Red Hat
 # see file 'COPYING' for use and warranty information
@@ -23,6 +24,7 @@
 Test the `ipalib/plugins/user.py` module.
 """
 
+import pytest
 import functools
 import datetime
 import ldap
@@ -33,41 +35,38 @@ from ipatests.test_xmlrpc import objectclasses
 from ipatests.util import (
     assert_equal, assert_not_equal, raises, assert_deepequal)
 from xmlrpc_test import (
-    XMLRPC_test, Declarative, fuzzy_digits, fuzzy_uuid, fuzzy_password,
+    XMLRPC_test, fuzzy_digits, fuzzy_uuid, fuzzy_password,
     fuzzy_string, fuzzy_dergeneralizedtime, add_sid, add_oc, raises_exact)
 from ipapython.dn import DN
 from ipatests.test_xmlrpc.ldaptracker import Tracker
 import pytest
 
-user1 = u'tuser1'
-user2 = u'tuser2'
 admin1 = u'admin'
-admin2 = u'admin2'
-renameduser1 = u'tuser'
 group1 = u'group1'
-admins_group = u'admins'
+admin_group = u'admins'
 
 invaliduser1 = u'+tuser1'
 invaliduser2 = u'tuser1234567890123456789012345678901234567890'
 
 sshpubkey = (u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDGAX3xAeLeaJggwTqMjxNwa6X'
-              'HBUAikXPGMzEpVrlLDCZtv00djsFTBi38PkgxBJVkgRWMrcBsr/35lq7P6w8KGI'
-              'wA8GI48Z0qBS2NBMJ2u9WQ2hjLN6GdMlo77O0uJY3251p12pCVIS/bHRSq8kHO2'
-              'No8g7KA9fGGcagPfQH+ee3t7HUkpbQkFTmbPPN++r3V8oVUk5LxbryB3UIIVzNm'
-              'cSIn3JrXynlvui4MixvrtX6zx+O/bBo68o8/eZD26QrahVbA09fivrn/4h3TM01'
-              '9Eu/c2jOdckfU3cHUV/3Tno5d6JicibyaoDDK7S/yjdn5jhaz8MSEayQvFkZkiF'
-              '0L public key test')
+             'HBUAikXPGMzEpVrlLDCZtv00djsFTBi38PkgxBJVkgRWMrcBsr/35lq7P6w8KGI'
+             'wA8GI48Z0qBS2NBMJ2u9WQ2hjLN6GdMlo77O0uJY3251p12pCVIS/bHRSq8kHO2'
+             'No8g7KA9fGGcagPfQH+ee3t7HUkpbQkFTmbPPN++r3V8oVUk5LxbryB3UIIVzNm'
+             'cSIn3JrXynlvui4MixvrtX6zx+O/bBo68o8/eZD26QrahVbA09fivrn/4h3TM01'
+             '9Eu/c2jOdckfU3cHUV/3Tno5d6JicibyaoDDK7S/yjdn5jhaz8MSEayQvFkZkiF'
+             '0L public key test')
 sshpubkeyfp = (u'13:67:6B:BF:4E:A2:05:8E:AE:25:8B:A1:31:DE:6F:1B '
-                'public key test (ssh-rsa)')
+               'public key test (ssh-rsa)')
 
-validlanguage1 = u'en-US;q=0.987 , en, abcdfgh-abcdefgh;q=1        , a;q=1.000'
-validlanguage2 = u'*'
+validlanguages = {
+    u'en-US;q=0.987 , en, abcdfgh-abcdefgh;q=1        , a;q=1.000',
+    u'*'
+    }
 
-invalidlanguage1 = u'abcdfghji-abcdfghji'
-invalidlanguage2 = u'en-us;q=0,123'
-invalidlanguage3 = u'en-us;q=0.1234'
-invalidlanguage4 = u'en-us;q=1.1'
-invalidlanguage5 = u'en-us;q=1.0000'
+invalidlanguages = {
+    u'abcdfghji-abcdfghji', u'en-us;q=0,123',
+    u'en-us;q=0.1234', u'en-us;q=1.1', u'en-us;q=1.0000'
+    }
 
 principal_expiration_string = "2020-12-07T19:54:13Z"
 principal_expiration_date = datetime.datetime(2020, 12, 7, 19, 54, 13)
@@ -79,1583 +78,6 @@ expired_expiration_string = "1991-12-07T19:54:13Z"
 isodate_re = re.compile('^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$')
 
 
-def get_user_result(uid, givenname, sn, operation='show', omit=[],
-                    **overrides):
-    """Get a user result for a user-{add,mod,find,show} command
-
-    This gives the result as from a user_add(uid, givenname=givenname, sn=sn);
-    modifications to that can be specified in ``omit`` and ``overrides``.
-
-    The ``operation`` can be one of:
-    - add
-    - show
-    - show-all ((show with the --all flag)
-    - find
-    - mod
-
-    Attributes named in ``omit`` are removed from the result; any additional
-    or non-default values can be specified in ``overrides``.
-    """
-    # sn can be None; this should only be used from `get_admin_result`
-    cn = overrides.get('cn', ['%s %s' % (givenname, sn or '')])
-    cn[0] = cn[0].strip()
-    result = add_sid(dict(
-        homedirectory=[u'/home/%s' % uid],
-        loginshell=[u'/bin/sh'],
-        uid=[uid],
-        uidnumber=[fuzzy_digits],
-        gidnumber=[fuzzy_digits],
-        mail=[u'%s@%s' % (uid, api.env.domain)],
-        has_keytab=False,
-        has_password=False,
-    ))
-    if sn:
-        result['sn'] = [sn]
-    if givenname:
-        result['givenname'] = [givenname]
-    if operation in ('add', 'show', 'show-all', 'find'):
-        result.update(
-            dn=get_user_dn(uid),
-        )
-    if operation in ('add', 'show-all'):
-        result.update(
-            cn=cn,
-            displayname=cn,
-            gecos=cn,
-            initials=[givenname[0] + (sn or '')[:1]],
-            ipauniqueid=[fuzzy_uuid],
-            mepmanagedentry=[get_group_dn(uid)],
-            objectclass=add_oc(objectclasses.user, u'ipantuserattrs'),
-            krbprincipalname=[u'%s@%s' % (uid, api.env.realm)],
-        )
-    if operation in ('show', 'show-all', 'find', 'mod'):
-        result.update(
-            nsaccountlock=False,
-        )
-    if operation in ('add', 'show', 'show-all', 'mod'):
-        result.update(
-            memberof_group=[u'ipausers'],
-        )
-    for key in omit:
-        del result[key]
-    result.update(overrides)
-    return result
-
-
-def get_admin_result(operation='show', **overrides):
-    """Give the result for the default admin user
-
-    Any additional or non-default values can be given in ``overrides``.
-    """
-    result = get_user_result(u'admin', None, u'Administrator', operation,
-                             omit=['mail'],
-                             has_keytab=True,
-                             has_password=True,
-                             loginshell=[u'/bin/bash'],
-                             **overrides)
-    return result
-
-
-def get_user_dn(uid):
-    return DN(('uid', uid), api.env.container_user, api.env.basedn)
-
-
-def get_group_dn(cn):
-    return DN(('cn', cn), api.env.container_group, api.env.basedn)
-
-
-def upg_check(response):
-    """Check that the user was assigned to the corresponding private group."""
-    assert_equal(response['result']['uidnumber'],
-                 response['result']['gidnumber'])
-    return True
-
-
-def not_upg_check(response):
-    """
-    Check that the user was not assigned to the corresponding
-    private group.
-    """
-
-    assert_not_equal(response['result']['uidnumber'],
-                     response['result']['gidnumber'])
-    return True
-
-
-@pytest.mark.tier1
-class test_user(Declarative):
-
-    cleanup_commands = [
-        ('user_del', [user1, user2, renameduser1, admin2], {'continue': True}),
-        ('group_del', [group1], {}),
-        ('automember_default_group_remove', [], {'type': u'group'}),
-    ]
-
-    tests = [
-
-        dict(
-            desc='Try to retrieve non-existent "%s"' % user1,
-            command=('user_show', [user1], {}),
-            expected=errors.NotFound(reason=u'%s: user not found' % user1),
-        ),
-
-
-        dict(
-            desc='Try to update non-existent "%s"' % user1,
-            command=('user_mod', [user1], dict(givenname=u'Foo')),
-            expected=errors.NotFound(reason=u'%s: user not found' % user1),
-        ),
-
-
-        dict(
-            desc='Try to delete non-existent "%s"' % user1,
-            command=('user_del', [user1], {}),
-            expected=errors.NotFound(reason=u'%s: user not found' % user1),
-        ),
-
-
-        dict(
-            desc='Try to rename non-existent "%s"' % user1,
-            command=('user_mod', [user1],
-                     dict(setattr=u'uid=%s' % renameduser1)),
-            expected=errors.NotFound(reason=u'%s: user not found' % user1),
-        ),
-
-
-        dict(
-            desc='Create "%s"' % user1,
-            command=(
-                'user_add',
-                [user1],
-                dict(
-                    givenname=u'Test',
-                    sn=u'User1',
-                    userclass=u'testusers'
-                )
-            ),
-            expected=dict(
-                value=user1,
-                summary=u'Added user "%s"' % user1,
-                result=get_user_result(
-                    user1,
-                    u'Test',
-                    u'User1',
-                    'add',
-                    userclass=[u'testusers'],
-                    objectclass=add_oc(
-                        objectclasses.user,
-                        u'ipantuserattrs'
-                    ) + [u'ipauser']
-                ),
-            ),
-            extra_check = upg_check,
-        ),
-
-
-        dict(
-            desc='Try to create duplicate "%s"' % user1,
-            command=(
-                'user_add', [user1], dict(givenname=u'Test', sn=u'User1')
-            ),
-            expected=errors.DuplicateEntry(
-                message=u'user with name "%s" already exists' % user1),
-        ),
-
-
-        dict(
-            desc='Retrieve "%s"' % user1,
-            command=(
-                'user_show', [user1], {}
-            ),
-            expected=dict(
-                result=get_user_result(
-                    user1,
-                    u'Test',
-                    u'User1',
-                    'show',
-                    userclass=[u'testusers']
-                ),
-                value=user1,
-                summary=None,
-            ),
-        ),
-
-        dict(
-            desc='Remove userclass for user "%s"' % user1,
-            command=('user_mod', [user1], dict(userclass=u'')),
-            expected=dict(
-                result=get_user_result(user1, u'Test', u'User1', 'mod'),
-                value=user1,
-                summary=u'Modified user "%s"' % user1,
-            ),
-        ),
-
-        dict(
-            desc='Search for "%s" with all=True' % user1,
-            command=(
-                'user_find', [user1], {'all': True}
-            ),
-            expected=dict(
-                result=[
-                    get_user_result(
-                        user1,
-                        u'Test',
-                        u'User1',
-                        'show-all',
-                        objectclass=add_oc(
-                            objectclasses.user,
-                            u'ipantuserattrs'
-                        ) + [u'ipauser'],
-                        preserved=False
-                    ),
-                ],
-                summary=u'1 user matched',
-                count=1, truncated=False,
-            ),
-        ),
-
-
-        dict(
-            desc='Search for "%s" with pkey-only=True' % user1,
-            command=(
-                'user_find', [user1], {'pkey_only': True}
-            ),
-            expected=dict(
-                result=[
-                    {
-                        'dn': get_user_dn(user1),
-                        'uid': [user1],
-                    },
-                ],
-                summary=u'1 user matched',
-                count=1, truncated=False,
-            ),
-        ),
-
-
-        dict(
-            desc='Search for "%s" with minimal attributes' % user1,
-            command=(
-                'user_find', [user1], {}
-            ),
-            expected=dict(
-                result=[
-                    get_user_result(user1, u'Test', u'User1', 'find'),
-                ],
-                summary=u'1 user matched',
-                count=1,
-                truncated=False,
-            ),
-        ),
-
-
-        dict(
-            desc='Search for all users',
-            command=(
-                'user_find', [], {}
-            ),
-            expected=dict(
-                result=[
-                    get_admin_result('find'),
-                    get_user_result(user1, u'Test', u'User1', 'find'),
-                ],
-                summary=u'2 users matched',
-                count=2,
-                truncated=False,
-            ),
-        ),
-
-
-        dict(
-            desc='Search for all users with a limit of 1',
-            command=(
-                'user_find', [], dict(sizelimit=1,),
-            ),
-            expected=dict(
-                result=[get_admin_result('find')],
-                summary=u'1 user matched',
-                count=1,
-                truncated=True,
-            ),
-        ),
-
-
-        dict(
-            desc='Disable "%s"' % user1,
-            command=(
-                'user_disable', [user1], {}
-            ),
-            expected=dict(
-                result=True,
-                value=user1,
-                summary=u'Disabled user account "%s"' % user1,
-            ),
-        ),
-
-        dict(
-            desc='Assert user is disabled',
-            command=('user_find', [user1], {}),
-            expected=dict(
-                result=[get_user_result(user1, u'Test', u'User1', 'find',
-                                        nsaccountlock=True)],
-                summary=u'1 user matched',
-                count=1,
-                truncated=False,
-            ),
-        ),
-
-        dict(
-            desc='Enable "%s"' % user1,
-            command=(
-                'user_enable', [user1], {}
-            ),
-            expected=dict(
-                result=True,
-                value=user1,
-                summary=u'Enabled user account "%s"' % user1,
-            ),
-        ),
-
-        dict(
-            desc='Assert user "%s" is enabled' % user1,
-            command=('user_find', [user1], {}),
-            expected=dict(
-                result=[get_user_result(user1, u'Test', u'User1', 'find')],
-                summary=u'1 user matched',
-                count=1,
-                truncated=False,
-            ),
-        ),
-
-        dict(
-            desc='Disable "%s" using setattr' % user1,
-            command=('user_mod', [user1], dict(setattr=u'nsaccountlock=True')),
-            expected=dict(
-                result=get_user_result(user1, u'Test', u'User1', 'mod',
-                                       nsaccountlock=True),
-                value=user1,
-                summary=u'Modified user "%s"' % user1,
-            ),
-        ),
-
-        dict(
-            desc='Enable "%s" using setattr' % user1,
-            command=('user_mod', [user1], dict(setattr=u'nsaccountlock=False')),
-            expected=dict(
-                result=get_user_result(user1, u'Test', u'User1', 'mod'),
-                value=user1,
-                summary=u'Modified user "%s"' % user1,
-            ),
-        ),
-
-        dict(
-            desc='Disable "%s" using user_mod' % user1,
-            command=('user_mod', [user1], dict(nsaccountlock=True)),
-            expected=dict(
-                result=get_user_result(user1, u'Test', u'User1', 'mod',
-                                       nsaccountlock=True),
-                value=user1,
-                summary=u'Modified user "%s"' % user1,
-            ),
-        ),
-
-        dict(
-            desc='Enable "%s" using user_mod' % user1,
-            command=('user_mod', [user1], dict(nsaccountlock=False)),
-            expected=dict(
-                result=get_user_result(user1, u'Test', u'User1', 'mod'),
-                value=user1,
-                summary=u'Modified user "%s"' % user1,
-            ),
-        ),
-
-        dict(
-            desc='Try setting virtual attribute on "%s" using setattr' % user1,
-            command=('user_mod', [user1], dict(setattr=u'random=xyz123')),
-            expected=errors.ObjectclassViolation(
-                info='attribute "random" not allowed'),
-        ),
-
-        dict(
-            desc='Update "%s"' % user1,
-            command=(
-                'user_mod', [user1], dict(givenname=u'Finkle')
-            ),
-            expected=dict(
-                result=get_user_result(user1, u'Finkle', u'User1', 'mod'),
-                summary=u'Modified user "%s"' % user1,
-                value=user1,
-            ),
-        ),
-
-
-        dict(
-            desc='Try updating the krb ticket policy of "%s"' % user1,
-            command=(
-                'user_mod', [user1], dict(setattr=u'krbmaxticketlife=88000')
-            ),
-            expected=errors.ObjectclassViolation(
-                info=u'attribute "krbmaxticketlife" not allowed'),
-        ),
-
-
-        dict(
-            desc='Retrieve "%s" to verify update' % user1,
-            command=('user_show', [user1], {}),
-            expected=dict(
-                result=get_user_result(user1, u'Finkle', u'User1', 'show'),
-                summary=None,
-                value=user1,
-            ),
-
-        ),
-
-
-        dict(
-            desc='Rename "%s"' % user1,
-            command=('user_mod', [user1],
-                     dict(setattr=u'uid=%s' % renameduser1)),
-            expected=dict(
-                result=get_user_result(
-                    renameduser1, u'Finkle', u'User1', 'mod',
-                    mail=[u'%s@%s' % (user1, api.env.domain)],
-                    homedirectory=[u'/home/%s' % user1]),
-                summary=u'Modified user "%s"' % user1,
-                value=user1,
-            ),
-        ),
-
-
-        dict(
-            desc='Rename "%s" to same value' % renameduser1,
-            command=('user_mod', [renameduser1],
-                     dict(setattr=u'uid=%s' % renameduser1)),
-            expected=errors.EmptyModlist(),
-        ),
-
-        dict(
-            desc='Rename "%s" to same value, check that other modifications '
-                 'are performed' % renameduser1,
-            command=('user_mod', [renameduser1],
-                     dict(setattr=u'uid=%s' % renameduser1,
-                          loginshell=u'/bin/bash')),
-            expected=dict(
-                result=get_user_result(
-                    renameduser1, u'Finkle', u'User1', 'mod',
-                    mail=[u'%s@%s' % (user1, api.env.domain)],
-                    homedirectory=[u'/home/%s' % user1],
-                    loginshell=[u'/bin/bash']),
-                summary=u'Modified user "%s"' % renameduser1,
-                value=renameduser1,
-            ),
-        ),
-
-
-        dict(
-            desc='Rename back "%s"' % renameduser1,
-            command=('user_mod', [renameduser1],
-                     dict(setattr=u'uid=%s' % user1, loginshell=u'/bin/sh')),
-            expected=dict(
-                result=get_user_result(user1, u'Finkle', u'User1', 'mod'),
-                summary=u'Modified user "%s"' % renameduser1,
-                value=renameduser1,
-            ),
-        ),
-
-
-        dict(
-            desc='Delete "%s"' % user1,
-            command=('user_del', [user1], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "%s"' % user1,
-                value=[user1],
-            ),
-        ),
-
-
-        dict(
-            desc='Try to delete non-existent "%s"' % user1,
-            command=('user_del', [user1], {}),
-            expected=errors.NotFound(reason=u'tuser1: user not found'),
-        ),
-
-
-        dict(
-            desc='Create user "%s" with krb ticket policy' % user1,
-            command=(
-                'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
-                setattr=u'krbmaxticketlife=88000')
-            ),
-            expected=errors.ObjectclassViolation(
-                info='attribute "krbmaxticketlife" not allowed'),
-        ),
-
-
-        dict(
-            desc='Create "%s" with SSH public key' % user1,
-            command=(
-                'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
-                                          ipasshpubkey=[sshpubkey])
-            ),
-            expected=dict(
-                value=user1,
-                summary=u'Added user "%s"' % user1,
-                result=get_user_result(
-                    user1, u'Test', u'User1', 'add',
-                    objectclass=add_oc(objectclasses.user, u'ipantuserattrs'),
-                    ipasshpubkey=[sshpubkey],
-                    sshpubkeyfp=[sshpubkeyfp],
-                ),
-            ),
-            extra_check = upg_check,
-        ),
-
-
-        dict(
-            desc='Add an illegal SSH public key to "%r"' % user1,
-            command=('user_mod', [user1],
-                     dict(ipasshpubkey=[u"anal nathrach orth' bhais's bethad "
-                                         "do che'l de'nmha"])),
-            expected=errors.ValidationError(name='sshpubkey',
-                error=u'invalid SSH public key'),
-        ),
-
-
-        dict(
-            desc='Delete "%s"' % user1,
-            command=('user_del', [user1], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "%s"' % user1,
-                value=[user1],
-            ),
-        ),
-
-
-        dict(
-            desc='Create "%s"' % user1,
-            command=(
-                'user_add', [user1], 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'),
-            ),
-            extra_check = upg_check,
-        ),
-
-
-        dict(
-            desc='Create "%s"' % user2,
-            command=(
-                'user_add', [user2], dict(givenname=u'Test', sn=u'User2')
-            ),
-            expected=dict(
-                value=user2,
-                summary=u'Added user "%s"' % user2,
-                result=get_user_result(user2, u'Test', u'User2', 'add'),
-            ),
-            extra_check = upg_check,
-        ),
-
-
-        dict(
-            desc='Make non-existent "%s" the manager of "%s"' % (renameduser1,
-                                                                 user2),
-            command=('user_mod', [user2], dict(manager=renameduser1)),
-            expected=errors.NotFound(
-                reason=u'manager %s not found' % renameduser1),
-        ),
-
-
-        dict(
-            desc='Make "%s" the manager of "%s"' % (user1, user2),
-            command=('user_mod', [user2], dict(manager=user1)),
-            expected=dict(
-                result=get_user_result(user2, u'Test', u'User2', 'mod',
-                                       manager=[user1]),
-                summary=u'Modified user "%s"' % user2,
-                value=user2,
-            ),
-        ),
-
-        dict(
-            desc='Search for "%s" with manager "%s"' % (user2, user1),
-            command=(
-                'user_find', [user2], {'manager': user1}
-            ),
-            expected=dict(
-                result=[get_user_result(user2, u'Test', u'User2', 'find',
-                                        manager=[user1])],
-                summary=u'1 user matched',
-                count=1,
-                truncated=False,
-            ),
-        ),
-
-        dict(
-            desc='Delete "%s" and "%s" at the same time' % (user1, user2),
-            command=('user_del', [user1, user2], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "tuser1,tuser2"',
-                value=[user1, user2],
-            ),
-        ),
-
-        dict(
-            desc='Try to retrieve non-existent "%s"' % user1,
-            command=('user_show', [user1], {}),
-            expected=errors.NotFound(reason=u'%s: user not found' % user1),
-        ),
-
-
-        dict(
-            desc='Try to update non-existent "%s"' % user1,
-            command=('user_mod', [user1], dict(givenname=u'Foo')),
-            expected=errors.NotFound(reason=u'%s: user not found' % user1),
-        ),
-
-
-        dict(
-            desc='Test an invalid login name "%s"' % invaliduser1,
-            command=('user_add', [invaliduser1], dict(givenname=u'Test',
-                                                      sn=u'User1')),
-            expected=errors.ValidationError(name='login',
-                error=u'may only include letters, numbers, _, -, . and $'),
-        ),
-
-
-        dict(
-            desc='Test a login name that is too long "%s"' % invaliduser2,
-            command=('user_add', [invaliduser2],
-                dict(givenname=u'Test', sn=u'User1')),
-            expected=errors.ValidationError(name='login',
-                error='can be at most 32 characters'),
-        ),
-
-
-        # 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 deletes',
-            command=('user_del', [invaliduser1], {}),
-            expected=errors.NotFound(
-                reason=u'%s: user not found' % invaliduser1),
-        ),
-
-
-        dict(
-            desc='Test that validation is disabled on show',
-            command=('user_show', [invaliduser1], {}),
-            expected=errors.NotFound(
-                reason=u'%s: user not found' % invaliduser1),
-        ),
-
-
-        dict(
-            desc='Test that validation is disabled on find',
-            command=('user_find', [invaliduser1], {}),
-            expected=dict(
-                count=0,
-                truncated=False,
-                summary=u'0 users matched',
-                result=[],
-            ),
-        ),
-
-
-        dict(
-            desc='Try to rename to invalid username "%s"' % user1,
-            command=('user_mod', [user1], dict(rename=invaliduser1)),
-            expected=errors.ValidationError(name='rename',
-                error=u'may only include letters, numbers, _, -, . and $'),
-        ),
-
-
-        dict(
-            desc='Try to rename to a username that is too long "%s"' % user1,
-            command=('user_mod', [user1], dict(rename=invaliduser2)),
-            expected=errors.ValidationError(name='login',
-                error='can be at most 32 characters'),
-        ),
-
-
-        dict(
-            desc='Create "%s"' % group1,
-            command=(
-                'group_add', [group1], dict(description=u'Test desc')
-            ),
-            expected=dict(
-                value=group1,
-                summary=u'Added group "%s"' % group1,
-                result=dict(
-                    cn=[group1],
-                    description=[u'Test desc'],
-                    gidnumber=[fuzzy_digits],
-                    objectclass=objectclasses.group + [u'posixgroup'],
-                    ipauniqueid=[fuzzy_uuid],
-                    dn=get_group_dn(group1),
-                ),
-            ),
-        ),
-
-
-        dict(
-            desc='Try to user "%s" where the managed group exists' % group1,
-            command=(
-                'user_add', [group1], dict(givenname=u'Test', sn=u'User1')
-            ),
-            expected=errors.ManagedGroupExistsError(group=group1)
-        ),
-
-
-        dict(
-            desc='Create "%s" with a full address' % user1,
-            command=(
-                'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
-                street=u'123 Maple Rd', l=u'Anytown', st=u'MD',
-                telephonenumber=u'410-555-1212', postalcode=u'01234-5678')
-            ),
-            expected=dict(
-                value=user1,
-                summary=u'Added user "%s"' % user1,
-                result=get_user_result(
-                    user1, u'Test', u'User1', 'add',
-                    street=[u'123 Maple Rd'], l=[u'Anytown'], st=[u'MD'],
-                    telephonenumber=[u'410-555-1212'],
-                    postalcode=[u'01234-5678'],
-                ),
-            ),
-        ),
-
-
-        dict(
-            desc='Delete "%s"' % user1,
-            command=('user_del', [user1], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "%s"' % user1,
-                value=[user1],
-            ),
-        ),
-
-        dict(
-            desc='Create "%s" with random password' % user1,
-            command=(
-                'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
-                                          random=True)
-            ),
-            expected=dict(
-                value=user1,
-                summary=u'Added user "%s"' % user1,
-                result=get_user_result(
-                    user1, u'Test', u'User1', 'add',
-                    randompassword=fuzzy_password,
-                    has_keytab=True, has_password=True,
-                    krbextradata=[fuzzy_string],
-                    krbpasswordexpiration=[fuzzy_dergeneralizedtime],
-                    krblastpwdchange=[fuzzy_dergeneralizedtime]
-                ),
-            ),
-        ),
-
-        dict(
-            desc='Delete "%s"' % user1,
-            command=('user_del', [user1], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "%s"' % user1,
-                value=[user1],
-            ),
-        ),
-
-        dict(
-            desc='Create "%s"' % user2,
-            command=(
-                'user_add', [user2], dict(givenname=u'Test', sn=u'User2')
-            ),
-            expected=dict(
-                value=user2,
-                summary=u'Added user "%s"' % user2,
-                result=get_user_result(user2, u'Test', u'User2', 'add'),
-            ),
-        ),
-
-        dict(
-            desc='Modify "%s" with random password' % user2,
-            command=(
-                'user_mod', [user2], dict(random=True)
-            ),
-            expected=dict(
-                result=get_user_result(
-                    user2, u'Test', u'User2', 'mod',
-                    randompassword=fuzzy_password,
-                    has_keytab=True, has_password=True,
-                ),
-                summary=u'Modified user "%s"' % user2,
-                value=user2,
-            ),
-        ),
-
-        dict(
-            desc='Delete "%s"' % user2,
-            command=('user_del', [user2], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "%s"' % user2,
-                value=[user2],
-            ),
-        ),
-
-        dict(
-            desc='Create user "%s" with upper-case principal' % user1,
-            command=(
-                'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
-                krbprincipalname=user1.upper())
-            ),
-            expected=dict(
-                value=user1,
-                summary=u'Added user "%s"' % user1,
-                result=get_user_result(user1, u'Test', u'User1', 'add'),
-            ),
-        ),
-
-
-        dict(
-            desc='Create user "%s" with bad realm in principal' % user1,
-            command=(
-                'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
-                krbprincipalname='%s...@notfound.org' % user1)
-            ),
-            expected=errors.RealmMismatch()
-        ),
-
-
-        dict(
-            desc='Create user "%s" with malformed principal' % user1,
-            command=(
-                'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
-                krbprincipalname='%s@b...@notfound.org' % user1)
-            ),
-            expected=errors.MalformedUserPrincipal(
-                principal='%s@b...@notfound.org' % user1),
-        ),
-
-        dict(
-            desc='Delete "%s"' % user1,
-            command=('user_del', [user1], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "%s"' % user1,
-                value=[user1],
-            ),
-        ),
-
-        dict(
-            desc='Change default home directory',
-            command=(
-                'config_mod', [], dict(ipahomesrootdir=u'/other-home'),
-            ),
-            expected=lambda x, output: x is None,
-        ),
-
-        dict(
-            desc=('Create user "%s" with different default '
-                  'home directory' % user1),
-            command=(
-                'user_add', [user1], 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',
-                                       homedirectory=[u'/other-home/tuser1']),
-            ),
-        ),
-
-
-        dict(
-            desc='Reset default home directory',
-            command=(
-                'config_mod', [], dict(ipahomesrootdir=u'/home'),
-            ),
-            expected=lambda x, output: x is None,
-        ),
-
-        dict(
-            desc='Delete "%s"' % user1,
-            command=('user_del', [user1], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "%s"' % user1,
-                value=[user1],
-            ),
-        ),
-
-        dict(
-            desc='Change default login shell',
-            command=(
-                'config_mod', [],
-                dict(ipadefaultloginshell=u'/usr/bin/ipython'),
-            ),
-            expected=lambda x, output: x is None,
-        ),
-
-        dict(
-            desc='Create user "%s" with different default login shell' % user1,
-            command=(
-                'user_add', [user1], 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',
-                                       loginshell=[u'/usr/bin/ipython']),
-            ),
-        ),
-
-        dict(
-            desc='Reset default login shell',
-            command=(
-                'config_mod', [], dict(ipadefaultloginshell=u'/bin/sh'),
-            ),
-            expected=lambda x, output: x is None,
-        ),
-
-        dict(
-            desc='Delete "%s"' % user1,
-            command=('user_del', [user1], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "%s"' % user1,
-                value=[user1],
-            ),
-        ),
-
-        dict(
-            desc='Create "%s" without UPG' % user1,
-            command=(
-                'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
-                                          noprivate=True)
-            ),
-            expected=errors.NotFound(
-                reason='Default group for new users is not POSIX'),
-        ),
-
-        dict(
-            desc='Create "%s" without UPG with GID explicitly set' % user2,
-            command=(
-                'user_add', [user2], dict(givenname=u'Test', sn=u'User2',
-                                          noprivate=True, gidnumber=1000)
-            ),
-            expected=dict(
-                value=user2,
-                summary=u'Added user "%s"' % user2,
-                result=get_user_result(
-                    user2, u'Test', u'User2', 'add',
-                    objectclass=add_oc(objectclasses.user_base,
-                                       u'ipantuserattrs'),
-                    gidnumber=[u'1000'],
-                    description=[],
-                    omit=['mepmanagedentry'],
-                ),
-            ),
-        ),
-
-        dict(
-            desc='Delete "%s"' % user2,
-            command=('user_del', [user2], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "%s"' % user2,
-                value=[user2],
-            ),
-        ),
-
-        dict(
-            desc='Change default user group',
-            command=(
-                'config_mod', [], dict(ipadefaultprimarygroup=group1),
-            ),
-            expected=lambda x, output: x is None,
-        ),
-
-        dict(
-            desc='Create "%s" without UPG' % user1,
-            command=(
-                'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
-                                          noprivate=True)
-            ),
-            expected=dict(
-                value=user1,
-                summary=u'Added user "%s"' % user1,
-                result=get_user_result(
-                    user1, u'Test', u'User1', 'add',
-                    objectclass=add_oc(objectclasses.user_base,
-                                       u'ipantuserattrs'),
-                    description=[],
-                    memberof_group=[group1],
-                    omit=['mepmanagedentry'],
-                ),
-            ),
-            extra_check = not_upg_check,
-        ),
-
-        dict(
-            desc='Create "%s" without UPG with GID explicitly set' % user2,
-            command=(
-                'user_add', [user2], dict(givenname=u'Test', sn=u'User2',
-                                          noprivate=True, gidnumber=1000)
-            ),
-            expected=dict(
-                value=user2,
-                summary=u'Added user "%s"' % user2,
-                result=get_user_result(
-                    user2, u'Test', u'User2', 'add',
-                    objectclass=add_oc(objectclasses.user_base,
-                                       u'ipantuserattrs'),
-                    description=[],
-                    gidnumber=[u'1000'],
-                    memberof_group=[group1],
-                    omit=['mepmanagedentry'],
-                ),
-            ),
-        ),
-
-        dict(
-            desc='Set %r as manager of %r' % (user1, user2),
-            command=(
-                'user_mod', [user2], dict(manager=user1)
-            ),
-            expected=dict(
-                result=get_user_result(user2, u'Test', u'User2', 'mod',
-                                       gidnumber=[u'1000'],
-                                       memberof_group=[group1],
-                                       manager=[user1]),
-                summary=u'Modified user "%s"' % user2,
-                value=user2,
-            ),
-        ),
-
-        dict(
-            desc='Rename "%s"' % user1,
-            command=('user_mod', [user1], dict(rename=renameduser1)),
-            expected=dict(
-                result=get_user_result(
-                    renameduser1, u'Test', u'User1', 'mod',
-                    homedirectory=[u'/home/%s' % user1],
-                    mail=[u'%s@%s' % (user1, api.env.domain)],
-                    memberof_group=[group1],
-                ),
-                summary=u'Modified user "%s"' % user1,
-                value=user1,
-            ),
-        ),
-
-        dict(
-            desc='Retrieve %r and check that manager is renamed' % user2,
-            command=(
-                'user_show', [user2], {'all': True}
-            ),
-            expected=dict(
-                result=get_user_result(
-                    user2, u'Test', u'User2', 'show-all',
-                    gidnumber=[u'1000'],
-                    memberof_group=[group1],
-                    manager=[renameduser1],
-                    objectclass=add_oc(objectclasses.user_base,
-                                       u'ipantuserattrs'),
-                    preserved=False,
-                    omit=['mepmanagedentry'],
-                ),
-                value=user2,
-                summary=None,
-            ),
-        ),
-
-        dict(
-            desc='Delete %r' % renameduser1,
-            command=('user_del', [renameduser1], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "%s"' % renameduser1,
-                value=[renameduser1],
-            ),
-        ),
-
-        dict(
-            desc='Retrieve %r and check that manager is gone' % user2,
-            command=(
-                'user_show', [user2], {'all': True}
-            ),
-            expected=dict(
-                result=get_user_result(
-                    user2, u'Test', u'User2', 'show-all',
-                    gidnumber=[u'1000'],
-                    memberof_group=[group1],
-                    objectclass=add_oc(objectclasses.user_base,
-                                       u'ipantuserattrs'),
-                    preserved=False,
-                    omit=['mepmanagedentry'],
-                ),
-                value=user2,
-                summary=None,
-            ),
-        ),
-
-        dict(
-            desc='Reset default user group',
-            command=(
-                'config_mod', [], dict(ipadefaultprimarygroup=u'ipausers'),
-            ),
-            expected=lambda x, output: x is None,
-        ),
-
-        dict(
-            desc='Try to remove the original admin user "%s"' % admin1,
-            command=('user_del', [admin1], {}),
-            expected=errors.LastMemberError(key=admin1, label=u'group',
-                container=admins_group),
-        ),
-
-        dict(
-            desc='Try to disable the original admin user "%s"' % admin1,
-            command=('user_disable', [admin1], {}),
-            expected=errors.LastMemberError(key=admin1, label=u'group',
-                container=admins_group),
-        ),
-
-
-        dict(
-            desc='Create 2nd admin user "%s"' % admin2,
-            command=(
-                'user_add', [admin2], dict(givenname=u'Second', sn=u'Admin')
-            ),
-            expected=dict(
-                value=admin2,
-                summary=u'Added user "%s"' % admin2,
-                result=get_user_result(admin2, u'Second', u'Admin', 'add'),
-            ),
-        ),
-
-        dict(
-            desc='Add "%s" to the admins group "%s"' % (admin2, admins_group),
-            command=('group_add_member', [admins_group], dict(user=admin2)),
-            expected=dict(
-                completed=1,
-                failed=dict(
-                    member=dict(
-                        group=tuple(),
-                        user=tuple(),
-                    ),
-                ),
-                result={
-                        'dn': get_group_dn(admins_group),
-                        'member_user': [admin1, admin2],
-                        'gidnumber': [fuzzy_digits],
-                        'cn': [admins_group],
-                        'description': [u'Account administrators group'],
-                },
-            ),
-        ),
-
-
-        dict(
-            desc=('Retrieve admins group "%s" to verify membership is '
-                  '"%s","%s"' % (admins_group, admin1, admin2)),
-            command=('group_show', [admins_group], {}),
-            expected=dict(
-                value=admins_group,
-                result=dict(
-                    cn=[admins_group],
-                    gidnumber=[fuzzy_digits],
-                    description=[u'Account administrators group'],
-                    dn=get_group_dn(admins_group),
-                    member_user=[admin1, admin2],
-                ),
-                summary=None,
-            ),
-        ),
-
-        dict(
-            desc=('Disable 2nd admin user "%s", admins group "%s" should also '
-                  'contain enabled "%s"' % (admin2, admins_group, admin1)),
-            command=(
-                'user_disable', [admin2], {}
-            ),
-            expected=dict(
-                result=True,
-                value=admin2,
-                summary=u'Disabled user account "%s"' % admin2,
-            ),
-        ),
-
-        dict(
-            desc='Assert 2nd admin user "%s" is disabled' % admin2,
-            command=('user_find', [admin2], {}),
-            expected=dict(
-                result=[lambda d: d['nsaccountlock'] is True],
-                summary=u'1 user matched',
-                count=1,
-                truncated=False,
-            ),
-        ),
-
-        dict(
-            desc='Try to disable the origin admin user "%s"' % admin1,
-            command=('user_disable', [admin1], {}),
-            expected=errors.LastMemberError(key=admin1, label=u'group',
-                container=admins_group),
-        ),
-
-        dict(
-            desc='Try to remove the original admin user "%s"' % admin1,
-            command=('user_del', [admin1], {}),
-            expected=errors.LastMemberError(key=admin1, label=u'group',
-                container=admins_group),
-        ),
-
-        dict(
-            desc='Delete 2nd admin "%s"' % admin2,
-            command=('user_del', [admin2], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "%s"' % admin2,
-                value=[admin2],
-            ),
-        ),
-
-        dict(
-            desc=('Retrieve admins group "%s" to verify membership is "%s"'
-                  % (admins_group, admin1)),
-            command=('group_show', [admins_group], {}),
-            expected=dict(
-                value=admins_group,
-                result=dict(
-                    cn=[admins_group],
-                    gidnumber=[fuzzy_digits],
-                    description=[u'Account administrators group'],
-                    dn=get_group_dn(admins_group),
-                    member_user=[admin1],
-                ),
-                summary=None,
-            ),
-        ),
-
-        dict(
-            desc='Assert original admin user "%s" is enabled' % admin1,
-            command=('user_find', [admin1], {}),
-            expected=dict(
-                result=[lambda d: d['nsaccountlock'] is False],
-                summary=u'1 user matched',
-                count=1,
-                truncated=False,
-            ),
-        ),
-
-        dict(
-            desc='Try to remove the original admin user "%s"' % admin1,
-            command=('user_del', [admin1], {}),
-            expected=errors.LastMemberError(key=admin1, label=u'group',
-                container=admins_group),
-        ),
-
-        dict(
-            desc='Try to disable the original admin user "%s"' % admin1,
-            command=('user_disable', [admin1], {}),
-            expected=errors.LastMemberError(key=admin1, label=u'group',
-                container=admins_group),
-        ),
-
-        dict(
-            desc='Set default automember group for groups as ipausers',
-            command=(
-                'automember_default_group_set', [], dict(
-                    type=u'group',
-                    automemberdefaultgroup=u'ipausers'
-                    )
-            ),
-            expected=dict(
-                result=dict(
-                    cn=[u'Group'],
-                    automemberdefaultgroup=[DN(('cn', 'ipausers'),
-                                               ('cn', 'groups'),
-                                               ('cn', 'accounts'),
-                                               api.env.basedn)],
-                ),
-                value=u'group',
-                summary=u'Set default (fallback) group for automember "group"',
-            ),
-        ),
-
-        dict(
-            desc='Delete "%s"' % user2,
-            command=('user_del', [user2], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "%s"' % user2,
-                value=[user2],
-            ),
-        ),
-
-        dict(
-            desc='Create %r' % user2,
-            command=(
-                'user_add', [user2], dict(givenname=u'Test', sn=u'User2')
-            ),
-            expected=dict(
-                value=user2,
-                summary=u'Added user "tuser2"',
-                result=get_user_result(user2, u'Test', u'User2', 'add'),
-            ),
-        ),
-
-        dict(
-            desc='Create "%s" with UID 999' % user1,
-            command=(
-                'user_add', [user1], dict(
-                    givenname=u'Test', sn=u'User1', uidnumber=999)
-            ),
-            expected=dict(
-                value=user1,
-                summary=u'Added user "%s"' % user1,
-                result=get_user_result(user1, u'Test', u'User1', 'add',
-                                       uidnumber=[u'999'],
-                                       gidnumber=[u'999']),
-            ),
-            extra_check = upg_check,
-        ),
-
-        dict(
-            desc='Delete "%s"' % user1,
-            command=('user_del', [user1], {}),
-            expected=dict(
-                result=dict(failed=[]),
-                summary=u'Deleted user "%s"' % user1,
-                value=[user1],
-            ),
-        ),
-
-        dict(
-            desc='Create "%s" with old DNA_MAGIC uid 999' % user1,
-            command=(
-                'user_add', [user1], dict(
-                    givenname=u'Test', sn=u'User1', uidnumber=999,
-                    version=u'2.49')
-            ),
-            expected=dict(
-                value=user1,
-                summary=u'Added user "%s"' % user1,
-                result=get_user_result(
-                    user1, u'Test', u'User1', 'add',
-                    uidnumber=[lambda v: int(v) != 999],
-                    gidnumber=[lambda v: int(v) != 999],
-                ),
-            ),
-            extra_check = upg_check,
-        ),
-
-        dict(
-            desc='Set ipauserauthtype for "%s"' % user1,
-            command=('user_mod', [user1], dict(ipauserauthtype=u'password')),
-            expected=dict(
-                result=get_user_result(user1, u'Test', u'User1', 'mod',
-                                       ipauserauthtype=[u'password'],
-                ),
-                value=user1,
-                summary='Modified user "%s"' % user1,
-            ),
-        ),
-
-        dict(
-            desc='Retrieve "%s" to verify ipauserauthtype' % user1,
-            command=('user_show', [user1], {}),
-            expected=dict(
-                result=get_user_result(user1, u'Test', u'User1', 'show',
-                                       ipauserauthtype=[u'password'],
-                ),
-                value=user1,
-                summary=None,
-            ),
-        ),
-
-        dict(
-            desc='Unset ipauserauthtype for "%s"' % user1,
-            command=('user_mod', [user1], dict(ipauserauthtype=None)),
-            expected=dict(
-                result=get_user_result(user1, u'Test', u'User1', 'mod'),
-                value=user1,
-                summary='Modified user "%s"' % user1,
-            ),
-        ),
-
-        dict(
-            desc='Query status of "%s"' % user1,
-            command=('user_status', [user1], {}),
-            expected=dict(
-                count=1,
-                result=[
-                    dict(
-                        dn=get_user_dn(user1),
-                        krblastfailedauth=[u'N/A'],
-                        krblastsuccessfulauth=[u'N/A'],
-                        krbloginfailedcount=u'0',
-                        now=isodate_re.match,
-                        server=api.env.host,
-                    ),
-                ],
-                summary=u'Account disabled: False',
-                truncated=False,
-            ),
-        ),
-
-        dict(
-            desc='Test an invalid preferredlanguage "%s"' % invalidlanguage1,
-            command=('user_mod', [user1],
-                     dict(preferredlanguage=invalidlanguage1)),
-            expected=errors.ValidationError(name='preferredlanguage',
-                error=(u'must match RFC 2068 - 14.4, e.g., '
-                        '"da, en-gb;q=0.8, en;q=0.7"')),
-        ),
-
-        dict(
-            desc='Test an invalid preferredlanguage "%s"' % invalidlanguage2,
-            command=('user_mod', [user1],
-                     dict(preferredlanguage=invalidlanguage2)),
-            expected=errors.ValidationError(name='preferredlanguage',
-                error=(u'must match RFC 2068 - 14.4, e.g., '
-                        '"da, en-gb;q=0.8, en;q=0.7"')),
-        ),
-
-        dict(
-            desc='Test an invalid preferredlanguage "%s"' % invalidlanguage3,
-            command=('user_mod', [user1],
-                     dict(preferredlanguage=invalidlanguage3)),
-            expected=errors.ValidationError(name='preferredlanguage',
-                error=(u'must match RFC 2068 - 14.4, e.g., '
-                        '"da, en-gb;q=0.8, en;q=0.7"')),
-        ),
-
-        dict(
-            desc='Test an invalid preferredlanguage "%s"' % invalidlanguage4,
-            command=('user_mod', [user1],
-                     dict(preferredlanguage=invalidlanguage4)),
-            expected=errors.ValidationError(name='preferredlanguage',
-                error=(u'must match RFC 2068 - 14.4, e.g., '
-                        '"da, en-gb;q=0.8, en;q=0.7"')),
-        ),
-
-        dict(
-            desc='Test an invalid preferredlanguage "%s"' % invalidlanguage5,
-            command=('user_mod', [user1],
-                     dict(preferredlanguage=invalidlanguage5)),
-            expected=errors.ValidationError(name='preferredlanguage',
-                error=(u'must match RFC 2068 - 14.4, e.g., '
-                        '"da, en-gb;q=0.8, en;q=0.7"')),
-        ),
-
-        dict(
-            desc='Set preferredlanguage "%s"' % validlanguage1,
-            command=('user_mod', [user1],
-                     dict(preferredlanguage=validlanguage1)),
-            expected=dict(
-                result=get_user_result(user1, u'Test', u'User1', 'mod',
-                                       preferredlanguage=[validlanguage1],
-                ),
-                value=user1,
-                summary='Modified user "%s"' % user1,
-            ),
-        ),
-
-        dict(
-            desc='Set preferredlanguage "%s"' % validlanguage2,
-            command=('user_mod', [user1],
-                     dict(preferredlanguage=validlanguage2)),
-            expected=dict(
-                result=get_user_result(user1, u'Test', u'User1', 'mod',
-                                       preferredlanguage=[validlanguage2],
-                ),
-                value=user1,
-                summary='Modified user "%s"' % user1,
-            ),
-        ),
-
-        dict(
-            desc='Set principal expiration "%s"' % principal_expiration_string,
-            command=('user_mod', [user1],
-                     dict(krbprincipalexpiration=principal_expiration_string)),
-            expected=dict(
-                result=get_user_result(user1, u'Test', u'User1', 'mod',
-                    krbprincipalexpiration=[principal_expiration_date],
-                ),
-                value=user1,
-                summary='Modified user "%s"' % user1,
-            ),
-        ),
-
-        dict(
-            desc='Set principal expiration "%s"' % invalid_expiration_string,
-            command=('user_mod', [user1],
-                     dict(krbprincipalexpiration=invalid_expiration_string)),
-            expected=errors.ConversionError(name='principal_expiration',
-                error=(u'does not match any of accepted formats: '
-                        '%Y%m%d%H%M%SZ, %Y-%m-%dT%H:%M:%SZ, %Y-%m-%dT%H:%MZ, '
-                        '%Y-%m-%dZ, %Y-%m-%d %H:%M:%SZ, %Y-%m-%d %H:%MZ')
-            ),
-        ),
-
-    ]
-
-
-@pytest.mark.tier1
-class test_denied_bind_with_expired_principal(XMLRPC_test):
-
-    password = u'random'
-
-    @classmethod
-    def setup_class(cls):
-        super(test_denied_bind_with_expired_principal, cls).setup_class()
-
-        cls.connection = ldap.initialize('ldap://{host}'
-                                         .format(host=api.env.host))
-
-    @classmethod
-    def teardown_class(cls):
-        cls.failsafe_del(api.Object.user, user1)
-        super(test_denied_bind_with_expired_principal, cls).teardown_class()
-
-    def test_1_bind_as_test_user(self):
-        self.failsafe_add(
-            api.Object.user,
-            user1,
-            givenname=u'Test',
-            sn=u'User1',
-            userpassword=self.password,
-            krbprincipalexpiration=principal_expiration_string
-        )
-
-        self.connection.simple_bind_s(str(get_user_dn(user1)), self.password)
-
-    def test_2_bind_as_expired_test_user(self):
-        api.Command['user_mod'](
-                user1,
-                krbprincipalexpiration=expired_expiration_string)
-
-        raises(ldap.UNWILLING_TO_PERFORM,
-               self.connection.simple_bind_s,
-               str(get_user_dn(user1)), self.password)
-
-    def test_3_bind_as_renewed_test_user(self):
-        api.Command['user_mod'](
-                user1,
-                krbprincipalexpiration=principal_expiration_string)
-
-        self.connection.simple_bind_s(str(get_user_dn(user1)), self.password)
-
-
 class UserTracker(Tracker):
     """ Class for host plugin like tests """
 
@@ -1668,13 +90,15 @@ class UserTracker(Tracker):
         u'krbprincipalexpiration', u'usercertificate', u'dn', u'has_keytab',
         u'has_password', u'street', u'postalcode', u'facsimiletelephonenumber',
         u'carlicense', u'ipasshpubkey', u'sshpubkeyfp', u'nsaccountlock',
-        u'preserved', u'memberof_group', u'l', u'mobile', u'krbextradata',
-        u'krblastpwdchange', u'krbpasswordexpiration', u'pager', u'st'
+        u'memberof_group', u'l', u'mobile', u'krbextradata',
+        u'krblastpwdchange', u'krbpasswordexpiration', u'pager', u'st',
+        u'manager'
         }
 
     retrieve_all_keys = retrieve_keys | {
         u'cn', u'ipauniqueid', u'objectclass', u'mepmanagedentry',
-        u'displayname', u'gecos', u'initials', u'krbprincipalname', u'manager'}
+        u'displayname', u'gecos', u'initials', u'krbprincipalname',
+        u'preserved'}
 
     retrieve_preserved_keys = retrieve_keys - {u'memberof_group'}
     retrieve_preserved_all_keys = retrieve_all_keys - {u'memberof_group'}
@@ -1682,14 +106,18 @@ class UserTracker(Tracker):
     create_keys = retrieve_all_keys | {
         u'randompassword', u'mepmanagedentry',
         u'krbextradata', u'krbpasswordexpiration', u'krblastpwdchange',
-        u'krbprincipalkey', u'randompassword', u'userpassword'
+        u'krbprincipalkey', u'userpassword'
         }
+    create_keys = create_keys - {u'nsaccountlock'}
+
     update_keys = retrieve_keys - {u'dn'}
     activate_keys = retrieve_all_keys - {u'has_keytab', u'has_password',
                                          u'nsaccountlock', u'sshpubkeyfp'}
 
     find_keys = retrieve_keys - {u'mepmanagedentry', u'memberof_group'}
-    find_all_keys = retrieve_all_keys - {u'mepmanagedentry', u'memberof_group'}
+    find_all_keys = retrieve_all_keys | {u'preserved'}
+
+    primary_keys = {u'uid', u'dn'}
 
     def __init__(self, name, givenname, sn, **kwargs):
         super(UserTracker, self).__init__(default_version=None)
@@ -1747,11 +175,18 @@ class UserTracker(Tracker):
         """ Make function that enables user using user-enable """
         return self.make_command('user_enable', self.uid)
 
+    def make_disable_command(self):
+        """ Make function that disables user using user-disable """
+        return self.make_command('user_disable', self.uid)
+
     def make_stage_command(self):
         """ Make function that restores preserved user by moving it to
         staged container """
         return self.make_command('user_stage', self.uid)
 
+    def make_group_add_member_command(self, *args, **kwargs):
+        return self.make_command('group_add_member', *args, **kwargs)
+
     def track_create(self):
         """ Update expected state for user creation """
         self.attrs = dict(
@@ -1774,27 +209,67 @@ class UserTracker(Tracker):
             loginshell=[u'/bin/sh'],
             has_keytab=False,
             has_password=False,
-            mepmanagedentry=[get_group_dn(self.uid)],
+            mepmanagedentry=[self.get_group_dn(self.uid)],
             memberof_group=[u'ipausers'],
+            nsaccountlock=[u'false'],
             )
 
         for key in self.kwargs:
             if key == u'krbprincipalname':
-                self.attrs[key] = [u'%s@%s' % (
-                    (self.kwargs[key].split('@'))[0].lower(),
-                    (self.kwargs[key].split('@'))[1]
+                try:
+                    self.attrs[key] = [u'%s@%s' % (
+                        (self.kwargs[key].split('@'))[0].lower(),
+                        (self.kwargs[key].split('@'))[1]
+                    )]
+                except IndexError as ex:
+                    # we can provide just principal part
+                    self.attrs[key] = [u'%s@%s' % (
+                        (self.kwargs[key].lower(),
+                         self.api.env.realm)
                     )]
             else:
                 self.attrs[key] = [self.kwargs[key]]
 
         self.exists = True
 
-    def check_create(self, result):
+    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 check_create(self, result, extra_keys=()):
         """ Check 'user-add' command result """
+        expected = self.filter_attrs(self.create_keys | set(extra_keys))
         assert_deepequal(dict(
             value=self.uid,
             summary=u'Added user "%s"' % self.uid,
-            result=self.filter_attrs(self.create_keys),
+            result=self.filter_attrs(expected),
             ), result)
 
     def check_delete(self, result):
@@ -1805,9 +280,8 @@ class UserTracker(Tracker):
             result=dict(failed=[]),
             ), result)
 
-    def check_retrieve(self, result, all=False):
+    def check_retrieve(self, result, all=False, raw=False):
         """ Check 'user-show' command result """
-
         if u'preserved' in self.attrs and self.attrs[u'preserved']:
             self.retrieve_all_keys = self.retrieve_preserved_all_keys
             self.retrieve_keys = self.retrieve_preserved_keys
@@ -1834,13 +308,15 @@ class UserTracker(Tracker):
             result=expected,
         ), result)
 
-    def check_find(self, result, all=False, raw=False):
+    def check_find(self, result, all=False, pkey_only=False, raw=False):
         """ Check 'user-find' command result """
-        self.attrs[u'nsaccountlock'] = True
-        self.attrs[u'preserved'] = True
+        self.attrs[u'nsaccountlock'] = False
+        self.attrs[u'preserved'] = False
 
         if all:
             expected = self.filter_attrs(self.find_all_keys)
+        elif pkey_only:
+            expected = self.filter_attrs(self.primary_keys)
         else:
             expected = self.filter_attrs(self.find_keys)
 
@@ -1862,10 +338,35 @@ class UserTracker(Tracker):
 
     def check_update(self, result, extra_keys=()):
         """ Check 'user-mod' command result """
+        # small override because stageuser-find returns different
+        # type of nsaccountlock value than DS, but overall the value
+        # fits expected result
+        expected = self.filter_attrs(self.update_keys | set(extra_keys))
+        if expected[u'nsaccountlock'] == [u'true']:
+            expected[u'nsaccountlock'] = True
+        elif expected[u'nsaccountlock'] == [u'false']:
+            expected[u'nsaccountlock'] = False
+
         assert_deepequal(dict(
             value=self.uid,
             summary=u'Modified user "%s"' % self.uid,
-            result=self.filter_attrs(self.update_keys | set(extra_keys))
+            result=expected
+        ), result)
+
+    def check_enable(self, result):
+        """ Check result of enable user operation """
+        assert_deepequal(dict(
+            value=self.name,
+            summary=u'Enabled user account "%s"' % self.name,
+            result=True
+        ), result)
+
+    def check_disable(self, result):
+        """ Check result of disable user operation """
+        assert_deepequal(dict(
+            value=self.name,
+            summary=u'Disabled user account "%s"' % self.name,
+            result=True
         ), result)
 
     def create_from_staged(self, stageduser):
@@ -1922,6 +423,22 @@ class UserTracker(Tracker):
             result=True
             ), result)
 
+    def enable(self):
+        """ Enable user account if it was disabled """
+        if (self.attrs['nsaccountlock'] is True or
+                self.attrs['nsaccountlock'] == [u'true']):
+            self.attrs.update(nsaccountlock=False)
+            result = self.make_enable_command()()
+            self.check_enable(result)
+
+    def disable(self):
+        """ Disable user account if it was enabled """
+        if (self.attrs['nsaccountlock'] is False or
+                self.attrs['nsaccountlock'] == [u'false']):
+            self.attrs.update(nsaccountlock=True)
+            result = self.make_disable_command()()
+            self.check_disable(result)
+
     def track_delete(self, preserve=False):
         """Update expected state for host deletion"""
         if preserve:
@@ -1983,3 +500,1067 @@ class UserTracker(Tracker):
         request.addfinalizer(finish)
 
         return self
+
+    def make_admin(self, admin_group=u'admins'):
+        """ Add user to the administrator's group """
+        result = self.run_command('group_show', admin_group)
+        admin_group_content = result[u'result'][u'member_user']
+        admin_group_expected = list(admin_group_content) + [self.name]
+
+        command = self.make_group_add_member_command(
+            admin_group, **dict(user=self.name)
+        )
+        result = command()
+        assert_deepequal(dict(
+            completed=1,
+            failed=dict(
+                member=dict(group=tuple(), user=tuple())
+            ),
+            result={
+                'dn': self.get_group_dn(admin_group),
+                'member_user': admin_group_expected,
+                'gidnumber': [fuzzy_digits],
+                'cn': [admin_group],
+                'description': [u'Account administrators group'],
+            },
+        ), result)
+
+    def get_group_dn(self, cn):
+        """ Get group DN by CN """
+        return DN(('cn', cn), api.env.container_group, api.env.basedn)
+
+    def get_user_dn(self, uid=None):
+        """ Get user DN by uid """
+        if not uid:
+            uid = self.uid
+
+        return DN(('uid', uid), api.env.container_user, api.env.basedn)
+
+
+@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 user2(request):
+    tracker = UserTracker(name=u'user2', givenname=u'Test2', sn=u'User2')
+    return tracker.make_fixture(request)
+
+
+@pytest.fixture(scope='class')
+def renameduser(request):
+    tracker = UserTracker(name=u'ruser1', givenname=u'Ruser', sn=u'Ruser1')
+    return tracker.make_fixture(request)
+
+
+@pytest.fixture(scope='class')
+def admin2(request):
+    tracker = UserTracker(name=u'admin2', givenname=u'Second', sn=u'Admin')
+    return tracker.make_fixture(request)
+
+
+@pytest.fixture(scope='class')
+def user_npg(request):
+    """ User tracker fixture for testing users with no private group """
+    tracker = UserTracker(name=u'npguser1', givenname=u'Npguser',
+                          sn=u'Npguser1', noprivate=True)
+    tracker.track_create()
+    del tracker.attrs['mepmanagedentry']
+    tracker.attrs.update(
+        description=[], memberof_group=[group1],
+        objectclass=add_oc(objectclasses.user_base, u'ipantuserattrs')
+    )
+    return tracker
+
+
+@pytest.fixture(scope='class')
+def user_npg2(request):
+    """ 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=[group1],
+        objectclass=add_oc(objectclasses.user_base, u'ipantuserattrs')
+    )
+    return tracker
+
+
+def create_test_group():
+    """ Create group for tests using users with an own group """
+    user = UserTracker(name=u'nonuser', givenname=u'Nuser', sn=u'Nuser1')
+    result = user.run_command(
+        'group_add', group1, **dict(description=u'Test desc')
+    )
+    assert_deepequal(dict(
+        value=group1,
+        summary=u'Added group "%s"' % group1,
+        result=dict(
+            cn=[group1],
+            description=[u'Test desc'],
+            gidnumber=[fuzzy_digits],
+            objectclass=objectclasses.group + [u'posixgroup'],
+            ipauniqueid=[fuzzy_uuid],
+            dn=user.get_group_dn(group1))
+    ), result)
+    user.ensure_missing()
+
+
+def delete_test_group():
+    """ Delete the group for tests using users with an own group """
+    tracker = Tracker()
+    tracker.run_command('group_del', group1)
+
+
+@pytest.mark.tier1
+class TestPrepare(XMLRPC_test):
+    def test_ensure_defaults_are_set(self):
+        """ Ensure expected default values are set prior running the tests """
+        tracker = Tracker()
+        mods = [{u'ipadefaultloginshell': u'/bin/sh'},
+                {u'ipahomesrootdir': u'/home'},
+                {u'ipadefaultprimarygroup': u'ipausers'}]
+
+        for mod in mods:
+            try:
+                tracker.run_command('config_mod', **mod)
+            except errors.EmptyModlist as ex:
+                pass
+
+    def test_purge_testusers(self):
+        """ Remove test users after previous test runs """
+        testusers = [u'user1', u'user2', u'ruser1', u'tuser1', u'npguser1',
+                     u'npguser2', u'renameduser', u'renamed_npg2', u'admin2',
+                     invaliduser1, invaliduser2]
+        tracker = Tracker()
+
+        for user in testusers:
+            try:
+                tracker.make_command('user_del', user)
+            except errors.NotFound as ex:
+                pass
+
+    def test_purge_testgroups(self):
+        """ Remove test groups after previous test runs """
+        testgroups = [group1]
+        tracker = Tracker()
+
+        for group in testgroups:
+            try:
+                tracker.make_command('group_del', group)
+            except errors.NotFound as ex:
+                pass
+
+
+@pytest.mark.tier1
+class TestNonexistentUser(XMLRPC_test):
+    def test_retrieve_nonexistent(self, user):
+        """ Try to retrieve a non-existent user """
+        user.ensure_missing()
+        command = user.make_retrieve_command()
+        with raises_exact(errors.NotFound(
+                reason=u'%s: user not found' % user.uid)):
+            command()
+
+    def test_update_nonexistent(self, user):
+        """ Try to update a non-existent user """
+        user.ensure_missing()
+        command = user.make_update_command(
+            updates=dict(givenname=u'changed'))
+        with raises_exact(errors.NotFound(
+                reason=u'%s: user not found' % user.uid)):
+            command()
+
+    def test_delete_nonexistent(self, user):
+        """ Try to delete a non-existent user """
+        user.ensure_missing()
+        command = user.make_delete_command()
+        with raises_exact(errors.NotFound(
+                reason=u'%s: user not found' % user.uid)):
+            command()
+
+    def test_rename_nonexistent(self, user, renameduser):
+        """ Try to rename a non-existent user """
+        user.ensure_missing()
+        command = user.make_update_command(
+            updates=dict(setattr=u'uid=%s' % renameduser.uid))
+        with raises_exact(errors.NotFound(
+                reason=u'%s: user not found' % user.uid)):
+            command()
+
+
+@pytest.mark.tier1
+class TestUser(XMLRPC_test):
+    def test_retrieve(self, user):
+        """ Create user and try to retrieve it """
+        user.retrieve()
+
+    def test_delete(self, user):
+        """ Delete user """
+        user.delete()
+
+    def test_query_status(self, user):
+        """ Query user_status on a user """
+        user.ensure_exists()
+        result = user.run_command('user_status', user.uid)
+        assert_deepequal(dict(
+            count=1,
+            result=[dict(
+                dn=user.dn,
+                krblastfailedauth=[u'N/A'],
+                krblastsuccessfulauth=[u'N/A'],
+                krbloginfailedcount=u'0',
+                now=isodate_re.match,
+                server=api.env.host,
+                ), ],
+            summary=u'Account disabled: False',
+            truncated=False,
+        ), result)
+        user.delete()
+
+    def test_remove_userclass(self, user):
+        """ Remove attribute userclass from user entry """
+        user.ensure_exists()
+        result = user.run_command(
+            'user_mod', user.uid, **dict(userclass=u'')
+        )
+        user.check_update(result)
+        user.delete()
+
+
+@pytest.mark.tier1
+class TestFind(XMLRPC_test):
+    def test_find(self, user):
+        """ Basic check of user-find """
+        user.find()
+
+    def test_find_with_all(self, user):
+        """ Basic check of user-find with --all """
+        user.find(all=True)
+
+    def test_find_with_pkey_only(self, user):
+        """ Basic check of user-find with primary keys only """
+        user.ensure_exists()
+        command = user.make_find_command(
+            uid=user.uid, pkey_only=True
+        )
+        result = command()
+        user.check_find(result, pkey_only=True)
+
+
+@pytest.mark.tier1
+class TestActive(XMLRPC_test):
+    def test_disable(self, user):
+        """ Disable user using user-disable """
+        user.ensure_exists()
+        user.disable()
+        command = user.make_retrieve_command()
+        result = command()
+        user.check_retrieve(result)
+
+    def test_enable(self, user):
+        """ Enable user using user-enable """
+        user.ensure_exists()
+        user.enable()
+        command = user.make_retrieve_command()
+        result = command()
+        user.check_retrieve(result)
+
+    def test_disable_using_setattr(self, user):
+        """ Disable user using setattr """
+        user.ensure_exists()
+        # we need to update the track manually
+        user.attrs['nsaccountlock'] = True
+
+        command = user.make_update_command(
+            updates=dict(setattr=u'nsaccountlock=True')
+        )
+        result = command()
+        user.check_update(result)
+
+    def test_enable_using_setattr(self, user):
+        """ Enable user using setattr """
+        user.ensure_exists()
+        user.attrs['nsaccountlock'] = False
+
+        command = user.make_update_command(
+            updates=dict(setattr=u'nsaccountlock=False')
+        )
+        result = command()
+        user.check_update(result)
+
+    def test_disable_using_usermod(self, user):
+        """ Disable user using user-mod """
+        user.update(dict(nsaccountlock=True), dict(nsaccountlock=True))
+
+    def test_enable_using_usermod(self, user):
+        """ Enable user using user-mod """
+        user.update(dict(nsaccountlock=False), dict(nsaccountlock=False))
+
+
+@pytest.mark.tier1
+class TestUpdate(XMLRPC_test):
+    def test_set_virtual_attribute(self, user):
+        """ Try to assign an invalid virtual attribute """
+        attr = 'random'
+        user.ensure_exists()
+        command = user.make_update_command(
+            updates=dict(setattr=(u'%s=xyz123' % attr))
+        )
+        with raises_exact(errors.ObjectclassViolation(
+                info=u'attribute "%s" not allowed' % attr)):
+            command()
+
+    def test_update(self, user):
+        """ Update a user attribute """
+        user.update(dict(givenname=u'Franta'))
+
+    def test_update_krb_ticket_policy(self, user):
+        """ Try to update krbmaxticketlife """
+        attr = 'krbmaxticketlife'
+        user.ensure_exists()
+        command = user.make_update_command(
+            updates=dict(setattr=(u'%s=88000' % attr))
+        )
+        with raises_exact(errors.ObjectclassViolation(
+                info=u'attribute "%s" not allowed' % attr)):
+            command()
+
+    def test_rename(self, user, renameduser):
+        """ Rename user and than rename it back """
+        user.ensure_exists()
+        renameduser.ensure_missing()
+        olduid = user.uid
+
+        # using user.update(dict(uid=value)) results in
+        # OverlapError: overlapping arguments and options: ['uid']
+        user.attrs.update(uid=[renameduser.uid])
+        command = user.make_update_command(
+            updates=dict(setattr=(u'uid=%s' % renameduser.uid))
+        )
+        result = command()
+        user.check_update(result)
+        user.uid = renameduser.uid
+
+        # rename the test user back so it gets properly deleted
+        user.attrs.update(uid=[olduid])
+        command = user.make_update_command(
+            updates=dict(setattr=(u'uid=%s' % olduid))
+        )
+        result = command()
+        user.check_update(result)
+        user.uid = olduid
+
+    def test_rename_to_the_same_value(self, user):
+        """ Try to rename user to the same value """
+        user.ensure_exists()
+        command = user.make_update_command(
+            updates=dict(setattr=(u'uid=%s' % user.uid))
+        )
+        with raises_exact(errors.EmptyModlist()):
+            command()
+
+    def test_rename_to_the_same_with_other_mods(self, user):
+        """ Try to rename user to the same value while
+        including other modifications that should be done """
+        user.ensure_exists()
+        user.attrs.update(loginshell=[u'/bin/false'])
+        command = user.make_update_command(
+            updates=dict(setattr=u'uid=%s' % user.uid,
+                         loginshell=u'/bin/false')
+        )
+        result = command()
+        user.check_update(result)
+
+    def test_rename_to_too_long_login(self, user):
+        """ Try to change user login to too long value """
+        user.ensure_exists()
+        command = user.make_update_command(
+            updates=dict(setattr=(u'uid=%s' % invaliduser2))
+            # no exception raised, user is renamed
+        )
+        try:
+            with raises_exact(errors.ValidationError(
+                    name='login',
+                    error=u'can be at most 32 characters')):
+                command()
+        # if the exception isn't raised, rename the user back
+        # so we can continue running
+        except AssertionError as ex:
+            command = user.make_command(
+                'user_mod', invaliduser2, **dict(rename=u'user1')
+            )
+            command()
+            raise ex
+
+    # FIXME skip this case as it crashes the server and we can't go on
+    def atest_rename_to_invalid_login(self, user):
+        """ Try to change user login to an invalid value """
+        user.ensure_exists()
+        command = user.make_update_command(
+            updates=dict(setattr=(u'uid=%s' % invaliduser1))
+            # crash
+        )
+        with raises_exact(errors.ValidationError(
+                name='rename',
+                error=u'may only include letters, numbers, _, -, . and $')):
+            command()
+
+    def test_update_illegal_ssh_pubkey(self, user):
+        """ Try to update user with an illegal SSH public key """
+        user.ensure_exists()
+        command = user.make_update_command(
+            updates=dict(ipasshpubkey=[u"anal nathrach orth' bhais's bethad "
+                                       "do che'l de'nmha"])
+        )
+        with raises_exact(errors.ValidationError(
+                name='sshpubkey',
+                error=u'invalid SSH public key')):
+            command()
+
+    def test_set_ipauserauthtype(self, user):
+        """ Set ipauserauthtype to 'password' and than back to None """
+        user.update(dict(ipauserauthtype=u'password'))
+        user.retrieve()
+
+        user.update(dict(ipauserauthtype=None))
+        user.delete()
+
+    def test_set_random_password(self, user):
+        """ Modify user with random password """
+        user.ensure_exists()
+        user.attrs.update(
+            randompassword=fuzzy_password,
+            has_keytab=True,
+            has_password=True
+        )
+        user.update(
+            dict(random=True),
+            dict(random=None, randompassword=fuzzy_password)
+        )
+        user.delete()
+
+
+@pytest.mark.tier1
+class TestCreate(XMLRPC_test):
+    def test_create_with_krb_ticket_policy(self):
+        """ Try to create user with krbmaxticketlife set """
+        testuser = UserTracker(
+            name=u'tuser1', givenname=u'Test',
+            sn=u'Tuser1', setattr=u'krbmaxticketlife=88000'
+        )
+        command = testuser.make_create_command()
+        with raises_exact(errors.ObjectclassViolation(
+                info=u'attribute "%s" not allowed' % 'krbmaxticketlife')):
+            command()
+
+    def test_create_with_ssh_pubkey(self):
+        """ Create user with an assigned SSH public key """
+        testuser = UserTracker(
+            name=u'tuser1', givenname=u'Test',
+            sn=u'Tuser1', ipasshpubkey=sshpubkey
+        )
+        testuser.track_create()
+        # fingerprint is expected in the tracker attrs
+        testuser.attrs.update(sshpubkeyfp=[sshpubkeyfp])
+        command = testuser.make_create_command()
+        result = command()
+        testuser.check_create(result)
+        testuser.delete()
+
+    def test_create_with_invalid_login(self):
+        """ Try to create user with an invalid login string """
+        testuser = UserTracker(
+            name=invaliduser1, givenname=u'Test', sn=u'User1'
+        )
+        command = testuser.make_create_command()
+        with raises_exact(errors.ValidationError(
+                name=u'login',
+                error=u'may only include letters, numbers, _, -, . and $')):
+            command()
+
+    def test_create_with_too_long_login(self):
+        """ Try to create user with too long login string """
+        testuser = UserTracker(
+            name=invaliduser2, givenname=u'Test', sn=u'User1'
+        )
+        command = testuser.make_create_command()
+        with raises_exact(errors.ValidationError(
+                name=u'login',
+                error=u'can be at most 32 characters')):
+            command()
+
+    def test_create_with_full_address(self):
+        """ Create user with full address set """
+        testuser = UserTracker(
+            name=u'tuser1', givenname=u'Test', sn=u'Tuser1',
+            street=u'123 Maple Rd', l=u'Anytown', st=u'MD',
+            postalcode=u'01234-5678', mobile=u'410-555-1212'
+        )
+        testuser.create()
+        testuser.delete()
+
+    def test_create_with_random_passwd(self):
+        """ Create user with random password """
+        testuser = UserTracker(
+            name=u'tuser1', givenname=u'Test', sn=u'Tuser1', random=True
+        )
+        testuser.track_create()
+        testuser.attrs.update(
+            randompassword=fuzzy_password,
+            has_keytab=True, has_password=True,
+            krbextradata=[fuzzy_string],
+            krbpasswordexpiration=[fuzzy_dergeneralizedtime],
+            krblastpwdchange=[fuzzy_dergeneralizedtime]
+        )
+        command = testuser.make_create_command()
+        result = command()
+        testuser.check_create(result)
+        testuser.delete()
+
+    def test_create_with_different_default_home(self, user):
+        """ Change default home directory and check that a newly created
+            user has his home set properly """
+        user.ensure_missing()
+        user.run_command('config_mod', **{u'ipahomesrootdir': u'/other-home'})
+        user.track_create()
+        user.attrs.update(homedirectory=[u'/other-home/%s' % user.name])
+
+        command = user.make_create_command()
+        result = command()
+        user.check_create(result)
+        user.run_command('config_mod', **{u'ipahomesrootdir': u'/home'})
+        user.delete()
+
+    def test_create_with_different_default_shell(self, user):
+        """ Change default login shell and check that a newly created
+            user is created with correct login shell value """
+        user.ensure_missing()
+        user.run_command(
+            'config_mod', **{u'ipadefaultloginshell': u'/bin/zsh'}
+        )
+        user.track_create()
+        user.attrs.update(loginshell=[u'/bin/zsh'])
+        command = user.make_create_command()
+        result = command()
+        user.check_create(result)
+        user.run_command(
+            'config_mod', **{u'ipadefaultloginshell': u'/bin/sh'}
+        )
+        user.delete()
+
+    def test_create_without_upg(self):
+        """ Try to create user without User's Primary GID """
+        testuser = UserTracker(
+            name=u'tuser1', givenname=u'Test', sn=u'Tuser1',
+            noprivate=True
+        )
+        command = testuser.make_create_command()
+        with raises_exact(errors.NotFound(
+                reason=u'Default group for new users is not POSIX')):
+            command()
+
+    def test_create_without_upg_with_gid_set(self):
+        """ Create user without User's Primary GID with GID set """
+        testuser = UserTracker(
+            name=u'tuser1', givenname=u'Test', sn=u'Tuser1',
+            noprivate=True, gidnumber=1000
+        )
+        testuser.track_create()
+        del testuser.attrs['mepmanagedentry']
+        testuser.attrs.update(gidnumber=[u'1000'])
+        testuser.attrs.update(
+            description=[],
+            objectclass=add_oc(objectclasses.user_base, u'ipantuserattrs')
+        )
+        command = testuser.make_create_command()
+        result = command()
+        testuser.check_create(result, [u'description'])
+        testuser.delete()
+
+    def test_create_with_uid_999(self):
+        """ Check that server return uid and gid 999
+        when a new client asks for uid 999 """
+        testuser = UserTracker(
+            name=u'tuser1', givenname=u'Test', sn=u'Tuser1', uidnumber=999
+        )
+        testuser.track_create()
+        testuser.attrs.update(
+            uidnumber=[u'999'],
+            gidnumber=[u'999']
+        )
+        command = testuser.make_create_command()
+        result = command()
+        testuser.check_create(result)
+        testuser.delete()
+
+    def test_create_with_old_DNA_MAGIC_999(self):
+        """ Check that server picks suitable uid and gid
+        when an old client asks for the magic uid 999 """
+        testuser = UserTracker(
+            name=u'tuser1', givenname=u'Test', sn=u'Tuser1',
+            uidnumber=999, version=u'2.49'
+        )
+        testuser.track_create()
+        testuser.attrs.update(
+            uidnumber=[lambda v: int(v) != 999],
+            gidnumber=[lambda v: int(v) != 999],
+        )
+        command = testuser.make_create_command()
+        result = command()
+        testuser.check_create(result)
+        testuser.delete()
+
+    def test_create_duplicate(self, user):
+        """ Try to create second user with the same name """
+        user.ensure_exists()
+        command = user.make_create_command()
+        with raises_exact(errors.DuplicateEntry(
+                message=u'user with name "%s" already exists' %
+                user.uid)):
+            command()
+
+    def test_create_where_managed_group_exists(self, user):
+        """ Create a managed group and then try to create user
+        with the same name the group has """
+        create_test_group()
+        command = user.make_command(
+            'user_add', group1, **dict(givenname=u'Test', sn=u'User1')
+        )
+        with raises_exact(errors.ManagedGroupExistsError(group=group1)):
+            command()
+
+        delete_test_group()
+
+
+@pytest.mark.tier1
+class TestUserWithGroup(XMLRPC_test):
+    def test_change_default_user_group(self):
+        """ Change default group for TestUserWithGroup class of tests """
+        create_test_group()
+        tracker = Tracker()
+        tracker.run_command(
+            'config_mod', **{u'ipadefaultprimarygroup': u'group1'}
+        )
+
+    def test_create_without_upg(self, user_npg):
+        """ Try to create user without User's Primary GID
+        after default group was changed """
+        command = user_npg.make_create_command()
+        # User without private group has some different attrs upon creation
+        # so we won't use make_create, but do own check instead
+        # These are set in the fixture
+        result = command()
+        user_npg.check_create(result, [u'description', u'memberof_group'])
+
+    def test_create_without_upg_with_gid_set(self, user_npg2):
+        """ Create user without User's Primary GID with GID set
+        after default group was changed """
+        command = user_npg2.make_create_command()
+        result = command()
+        user_npg2.check_create(result, [u'description', u'memberof_group'])
+
+    def test_set_manager(self, user_npg, user_npg2):
+        """ Update user with own group with manager with own group """
+        user_npg.update(dict(manager=user_npg2.uid))
+
+    def test_check_user_with_renamed_manager(self, user_npg, user_npg2):
+        """ Rename manager with own group, retrieve user and check
+            if its manager is also renamed """
+        renamed_name = u'renamed_npg2'
+        old_name = user_npg2.uid
+        command = user_npg2.make_update_command(dict(rename=renamed_name))
+        result = command()
+        user_npg2.attrs.update(uid=[renamed_name])
+        user_npg2.check_update(result)
+        user_npg.attrs.update(manager=[renamed_name])
+        user_npg.retrieve(all=True)
+
+        command = user_npg2.make_command(
+            'user_mod', renamed_name, **dict(rename=old_name)
+        )
+        # we rename the user back otherwise the tracker is too confused
+        result = command()
+
+    def test_check_if_manager_gets_removed(self, user_npg, user_npg2):
+        """ Delete manager and check if it's gone from user's attributes """
+        user_npg2.delete()
+        del user_npg.attrs[u'manager']
+        del user_npg.attrs[u'description']
+        user_npg.retrieve(all=True)
+
+    def test_change_default_user_group_back(self, user_npg, user_npg2):
+        """ Change default group back to 'ipausers' and clean up members """
+        user_npg.delete()
+        user_npg.run_command(
+            'config_mod', **{u'ipadefaultprimarygroup': u'ipausers'}
+        )
+        delete_test_group()
+
+
+@pytest.mark.tier1
+class TestManagers(XMLRPC_test):
+    def test_assign_nonexistent_manager(self, user, user2):
+        """ Try to assign user a non-existent manager """
+        user.ensure_exists()
+        user2.ensure_missing()
+        command = user.make_update_command(
+            updates=dict(manager=user2.uid)
+        )
+        with raises_exact(errors.NotFound(
+                reason=u'manager %s not found' % user2.uid)):
+            command()
+
+    def test_assign_manager(self, user, user2):
+        """ Make user manager of another user """
+        user.ensure_exists()
+        user2.ensure_exists()
+        user.update(dict(manager=user2.uid))
+
+    def test_search_by_manager(self, user, user2):
+        """ Find user by his manager's UID """
+        command = user.make_find_command(manager=user2.uid)
+        result = command()
+        user.check_find(result)
+
+    def test_delete_both_user_and_manager(self, user, user2):
+        """ Delete both user and its manager at once """
+        result = user.run_command(
+            'user_del', [user.uid, user2.uid],
+            preserve=False, no_preserve=True
+        )
+        assert_deepequal(dict(
+            value=[user.uid, user2.uid],
+            summary=u'Deleted user "%s,%s"' % (user.uid, user2.uid),
+            result=dict(failed=[]),
+            ), result)
+        # mark users as deleted
+        user.exists = False
+        user2.exists = False
+
+
+@pytest.mark.tier1
+class TestAdmins(XMLRPC_test):
+    def test_remove_original_admin(self):
+        """ Try to remove the only admin """
+        tracker = Tracker()
+        command = tracker.make_command('user_del', [admin1])
+
+        with raises_exact(errors.LastMemberError(
+                key=admin1, label=u'group', container=admin_group)):
+            command()
+
+    def test_disable_original_admin(self):
+        """ Try to disable the only admin """
+        tracker = Tracker()
+        command = tracker.make_command('user_disable', admin1)
+
+        with raises_exact(errors.LastMemberError(
+                key=admin1, label=u'group', container=admin_group)):
+            command()
+
+    def test_create_admin2(self, admin2):
+        """ Test whether second admin gets created """
+        admin2.ensure_exists()
+        admin2.make_admin()
+        admin2.delete()
+
+    def test_last_admin_preservation(self, admin2):
+        """ Create a second admin, disable it. Then try to disable and
+        remove the original one and receive LastMemberError. Last trial
+        are these ops with second admin removed. """
+        admin2.ensure_exists()
+        admin2.make_admin()
+        admin2.disable()
+        tracker = Tracker()
+
+        with raises_exact(errors.LastMemberError(
+                key=admin1, label=u'group', container=admin_group)):
+            tracker.run_command('user_disable', admin1)
+        with raises_exact(errors.LastMemberError(
+                key=admin1, label=u'group', container=admin_group)):
+            tracker.run_command('user_del', admin1)
+        admin2.delete()
+
+        with raises_exact(errors.LastMemberError(
+                key=admin1, label=u'group', container=admin_group)):
+            tracker.run_command('user_disable', admin1)
+        with raises_exact(errors.LastMemberError(
+                key=admin1, label=u'group', container=admin_group)):
+            tracker.run_command('user_del', admin1)
+
+
+@pytest.mark.tier1
+class TestPreferredLanguages(XMLRPC_test):
+    def test_invalid_preferred_languages(self, user):
+        """ Try to assign various invalid preferred languages to user """
+        user.ensure_exists()
+        for invalidlanguage in invalidlanguages:
+            command = user.make_update_command(
+                dict(preferredlanguage=invalidlanguage)
+            )
+
+            with raises_exact(errors.ValidationError(
+                    name='preferredlanguage',
+                    error=(u'must match RFC 2068 - 14.4, e.g., '
+                           '"da, en-gb;q=0.8, en;q=0.7"')
+            )):
+                command()
+        user.delete()
+
+    def test_valid_preferred_languages(self, user):
+        """ Update user with different preferred languages """
+        for validlanguage in validlanguages:
+            user.update(dict(preferredlanguage=validlanguage))
+        user.delete()
+
+
+@pytest.mark.tier1
+class TestPrincipals(XMLRPC_test):
+    def test_create_with_bad_realm_in_principal(self):
+        """ Try to create user with a bad realm in principal """
+        testuser = UserTracker(
+            name=u'tuser1', givenname=u'Test', sn=u'Tuser1',
+            krbprincipalname=u'tus...@notfound.org'
+        )
+
+        command = testuser.make_create_command()
+        with raises_exact(errors.RealmMismatch()):
+            command()
+
+    def test_create_with_malformed_principal(self):
+        """ Try to create user with wrongly formed principal """
+        testuser = UserTracker(
+            name=u'tuser1', givenname=u'Test', sn=u'Tuser1',
+            krbprincipalname=u'tuser1@b...@notfound.org'
+        )
+
+        command = testuser.make_create_command()
+        with raises_exact(errors.MalformedUserPrincipal(
+                principal=u'tuser1@b...@notfound.org')):
+            command()
+
+    def test_set_principal_expiration(self, user):
+        """ Set principal expiration for user """
+        user.update(
+            dict(krbprincipalexpiration=principal_expiration_string),
+            dict(krbprincipalexpiration=[principal_expiration_date])
+        )
+
+    def test_set_invalid_principal_expiration(self, user):
+        """ Try to set incorrent principal expiration value for user """
+        user.ensure_exists()
+        command = user.make_update_command(
+            dict(krbprincipalexpiration=invalid_expiration_string)
+        )
+
+        with raises_exact(errors.ConversionError(
+                name='principal_expiration',
+                error=(u'does not match any of accepted formats: '
+                       '%Y%m%d%H%M%SZ, %Y-%m-%dT%H:%M:%SZ, %Y-%m-%dT%H:%MZ, '
+                       '%Y-%m-%dZ, %Y-%m-%d %H:%M:%SZ, %Y-%m-%d %H:%MZ')
+        )):
+            command()
+
+    def test_create_with_uppercase_principal(self):
+        """ Create user with upper-case principal """
+        testuser = UserTracker(
+            name=u'tuser1', givenname=u'Test', sn=u'Tuser1',
+            krbprincipalname=u'tuser1'.upper()
+        )
+        testuser.create()
+        testuser.delete()
+
+
+@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_deletes(self):
+        """ Test that validation is disabled on user deletes """
+        tracker = Tracker()
+        command = tracker.make_command('user_del', invaliduser1)
+        with raises_exact(errors.NotFound(
+                reason=u'%s: user not found' % invaliduser1)):
+            command()
+
+    def test_validation_disabled_on_show(self):
+        """ Test that validation is disabled on user retrieves """
+        tracker = Tracker()
+        command = tracker.make_command('user_show', invaliduser1)
+        with raises_exact(errors.NotFound(
+                reason=u'%s: user not found' % invaliduser1)):
+            command()
+
+    def test_validation_disabled_on_find(self, user):
+        """ Test that validation is disabled on user searches """
+        result = user.run_command('user_find', invaliduser1)
+        user.check_find_nomatch(result)
+
+
+@pytest.mark.tier1
+class TestDeniedBindWithExpiredPrincipal(XMLRPC_test):
+
+    password = u'random'
+
+    @classmethod
+    def setup_class(cls):
+        super(TestDeniedBindWithExpiredPrincipal, cls).setup_class()
+
+        cls.connection = ldap.initialize('ldap://{host}'
+                                         .format(host=api.env.host))
+
+    @classmethod
+    def teardown_class(cls):
+        super(TestDeniedBindWithExpiredPrincipal, cls).teardown_class()
+
+    def test_bind_as_test_user(self, user):
+        """ Bind as user """
+        self.failsafe_add(
+            api.Object.user,
+            user.uid,
+            givenname=u'Test',
+            sn=u'User1',
+            userpassword=self.password,
+            krbprincipalexpiration=principal_expiration_string
+        )
+
+        self.connection.simple_bind_s(
+            str(user.get_user_dn()), self.password
+        )
+
+    def test_bind_as_expired_test_user(self, user):
+        """ Try to bind as expired user """
+        api.Command['user_mod'](
+            user.uid,
+            krbprincipalexpiration=expired_expiration_string
+        )
+
+        raises(ldap.UNWILLING_TO_PERFORM,
+               self.connection.simple_bind_s,
+               str(user.get_user_dn()), self.password
+               )
+
+    def test_bind_as_renewed_test_user(self, user):
+        """ Bind as renewed user """
+        api.Command['user_mod'](
+            user.uid,
+            krbprincipalexpiration=principal_expiration_string
+        )
+
+        self.connection.simple_bind_s(
+            str(user.get_user_dn()), self.password
+        )
+
+# This set of functions (get_*, upg_check, not_upg_check)
+# is mostly for legacy purposes here, tests using UserTracker
+# should not rely on them
+
+
+def get_user_result(uid, givenname, sn, operation='show', omit=[],
+                    **overrides):
+    """Get a user result for a user-{add,mod,find,show} command
+
+    This gives the result as from a user_add(uid, givenname=givenname, sn=sn);
+    modifications to that can be specified in ``omit`` and ``overrides``.
+
+    The ``operation`` can be one of:
+    - add
+    - show
+    - show-all ((show with the --all flag)
+    - find
+    - mod
+
+    Attributes named in ``omit`` are removed from the result; any additional
+    or non-default values can be specified in ``overrides``.
+    """
+    # sn can be None; this should only be used from `get_admin_result`
+    cn = overrides.get('cn', ['%s %s' % (givenname, sn or '')])
+    cn[0] = cn[0].strip()
+    result = add_sid(dict(
+        homedirectory=[u'/home/%s' % uid],
+        loginshell=[u'/bin/sh'],
+        uid=[uid],
+        uidnumber=[fuzzy_digits],
+        gidnumber=[fuzzy_digits],
+        mail=[u'%s@%s' % (uid, api.env.domain)],
+        has_keytab=False,
+        has_password=False,
+    ))
+    if sn:
+        result['sn'] = [sn]
+    if givenname:
+        result['givenname'] = [givenname]
+    if operation in ('add', 'show', 'show-all', 'find'):
+        result.update(
+            dn=get_user_dn(uid),
+        )
+    if operation in ('add', 'show-all'):
+        result.update(
+            cn=cn,
+            displayname=cn,
+            gecos=cn,
+            initials=[givenname[0] + (sn or '')[:1]],
+            ipauniqueid=[fuzzy_uuid],
+            mepmanagedentry=[get_group_dn(uid)],
+            objectclass=add_oc(objectclasses.user, u'ipantuserattrs'),
+            krbprincipalname=[u'%s@%s' % (uid, api.env.realm)],
+        )
+    if operation in ('show', 'show-all', 'find', 'mod'):
+        result.update(
+            nsaccountlock=False,
+        )
+    if operation in ('add', 'show', 'show-all', 'mod'):
+        result.update(
+            memberof_group=[u'ipausers'],
+        )
+    for key in omit:
+        del result[key]
+    result.update(overrides)
+    return result
+
+
+def get_admin_result(operation='show', **overrides):
+    """Give the result for the default admin user
+
+    Any additional or non-default values can be given in ``overrides``.
+    """
+    result = get_user_result(u'admin', None, u'Administrator', operation,
+                             omit=['mail'],
+                             has_keytab=True,
+                             has_password=True,
+                             loginshell=[u'/bin/bash'],
+                             **overrides)
+    return result
+
+
+def get_user_dn(uid):
+    """ Get user DN by uid """
+    return DN(('uid', uid), api.env.container_user, api.env.basedn)
+
+
+def get_group_dn(cn):
+    """ Get group DN by CN """
+    return DN(('cn', cn), api.env.container_group, api.env.basedn)
+
+
+def upg_check(response):
+    """Check that the user was assigned to the corresponding private group."""
+    assert_equal(response['result']['uidnumber'],
+                 response['result']['gidnumber'])
+    return True
+
+
+def not_upg_check(response):
+    """
+    Check that the user was not assigned to the corresponding
+    private group.
+    """
+
+    assert_not_equal(response['result']['uidnumber'],
+                     response['result']['gidnumber'])
+    return True
-- 
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

Reply via email to