def test_rename_to_same_value(self, idp): """ Try to rename idp to the same value """ idp.ensure_exists() command = idp.make_update_command(updates=dict(setattr=('cn=%s' % idp.cn))) with raises_exact(errors.EmptyModlist()): command()
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 execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) if not options['ipasudoopt'].strip(): raise errors.EmptyModlist() entry_attrs = ldap.get_entry(dn, ['ipasudoopt']) try: if options['ipasudoopt'] in entry_attrs['ipasudoopt']: entry_attrs.setdefault('ipasudoopt', []).remove(options['ipasudoopt']) ldap.update_entry(entry_attrs) else: raise errors.AttrValueNotFound(attr='ipasudoopt', value=options['ipasudoopt']) except ValueError: pass except KeyError: raise errors.AttrValueNotFound(attr='ipasudoopt', value=options['ipasudoopt']) except errors.NotFound: raise self.obj.handle_not_found(cn) attrs_list = self.obj.default_attributes entry_attrs = ldap.get_entry(dn, attrs_list) self.obj.get_indirect_members(entry_attrs, attrs_list) self.obj.convert_attribute_members(entry_attrs, [cn], **options) entry_attrs = entry_to_dict(entry_attrs, **options) return dict(result=entry_attrs, value=pkey_to_value(cn, options))
def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) if len(options.get('ipasudoopt', [])) == 0: raise errors.EmptyModlist() entry_attrs = ldap.get_entry(dn, ['ipasudoopt']) try: entry_attrs.setdefault('ipasudoopt', []) for option in options['ipasudoopt']: if option not in entry_attrs['ipasudoopt']: entry_attrs['ipasudoopt'].append(option) else: raise errors.DuplicateEntry except KeyError: entry_attrs.setdefault('ipasudoopt', []).append(options['ipasudoopt']) try: ldap.update_entry(entry_attrs) except errors.EmptyModlist: pass except errors.NotFound: raise self.obj.handle_not_found(cn) attrs_list = self.obj.default_attributes entry_attrs = ldap.get_entry(dn, attrs_list) self.obj.get_indirect_members(entry_attrs, attrs_list) self.obj.convert_attribute_members(entry_attrs, [cn], **options) entry_attrs = entry_to_dict(entry_attrs, **options) return dict(result=entry_attrs, value=pkey_to_value(cn, options))
def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) if not options['ipasudoopt'].strip(): raise errors.EmptyModlist() entry_attrs = ldap.get_entry(dn, ['ipasudoopt']) try: if options['ipasudoopt'] not in entry_attrs['ipasudoopt']: entry_attrs.setdefault('ipasudoopt', []).append( options['ipasudoopt']) else: raise errors.DuplicateEntry except KeyError: entry_attrs.setdefault('ipasudoopt', []).append( options['ipasudoopt']) try: ldap.update_entry(entry_attrs) except errors.EmptyModlist: pass except errors.NotFound: self.obj.handle_not_found(cn) attrs_list = self.obj.default_attributes entry_attrs = ldap.get_entry(dn, attrs_list) entry_attrs = entry_to_dict(entry_attrs, **options) return dict(result=entry_attrs, value=pkey_to_value(cn, options))
def execute(self, *keys, **options): ldap = self.obj.backend dn = self.obj.get_dn(*keys, **options) assert isinstance(dn, DN) newdn = None if options and 'ingroup' in options: group = options['ingroup'] if group: newdn = DN(('cn', keys[0]),('cn', group)) + self.obj.container_dn + self.obj.api.env.basedn else: newdn = DN(('cn', keys[0])) + self.obj.container_dn + self.obj.api.env.basedn else: raise errors.EmptyModlist() ldap.move_entry(dn, newdn) entry_attrs = ldap.get_entry(newdn) if group: entry_attrs['ingroup'] = group else: entry_attrs['ingroup'] = '--none--' entry_attrs = entry_to_dict(entry_attrs, **options) entry_attrs['dn'] = newdn pkey = keys[-1] return dict(result=entry_attrs, value=pkey_to_value(pkey, options))
class test_pwpolicy_mod_cospriority(Declarative): """Tests for cospriority modifications""" cleanup_commands = [ ('pwpolicy_del', [u'ipausers'], {}), ] tests = [ dict( desc='Create a password policy', command=('pwpolicy_add', [u'ipausers'], dict( krbmaxpwdlife=90, krbminpwdlife=1, krbpwdhistorylength=10, krbpwdmindiffchars=3, krbpwdminlength=8, cospriority=10, )), expected=dict( result=dict( cn=[u'ipausers'], cospriority=[u'10'], dn=DN('cn=ipausers', ('cn', api.env.realm), 'cn=kerberos', api.env.basedn), krbmaxpwdlife=[u'90'], krbminpwdlife=[u'1'], krbpwdhistorylength=[u'10'], krbpwdmindiffchars=[u'3'], krbpwdminlength=[u'8'], objectclass=objectclasses.pwpolicy, ), summary=None, value=u'ipausers', ), ), dict( # https://fedorahosted.org/freeipa/ticket/4309 desc="Try no-op modification of password policy's cospriority", command=('pwpolicy_mod', [u'ipausers'], dict(cospriority=10, )), expected=errors.EmptyModlist(), ), dict( desc="Modify the password policy's cospriority", command=('pwpolicy_mod', [u'ipausers'], dict(cospriority=20, )), expected=dict( result=dict( cn=[u'ipausers'], cospriority=[u'20'], krbmaxpwdlife=[u'90'], krbminpwdlife=[u'1'], krbpwdhistorylength=[u'10'], krbpwdmindiffchars=[u'3'], krbpwdminlength=[u'8'], ), summary=None, value=u'ipausers', ), ), ]
def group_mod_fas_precb(self, ldap, dn, entry_attrs, *keys, **options): """Add fasgroup object class """ if options.get("fasgroup", False): old_entry_attrs = ldap.get_entry(dn, ["objectclass"]) if "fasgroup" in old_entry_attrs["objectclass"]: raise errors.EmptyModlist( message=_("This is already a FAS group") ) old_entry_attrs["objectclass"].append("fasgroup") entry_attrs["objectclass"] = old_entry_attrs["objectclass"] return dn
def execute(self, aciname, **kw): aciprefix = kw['aciprefix'] ldap = self.api.Backend.ldap2 entry = ldap.get_entry(self.api.env.basedn, ['aci']) acis = _convert_strings_to_acis(entry.get('aci', [])) aci = _find_aci_by_name(acis, aciprefix, aciname) # The strategy here is to convert the ACI we're updating back into # a series of keywords. Then we replace any keywords that have been # updated and convert that back into an ACI and write it out. oldkw = _aci_to_kw(ldap, aci) newkw = deepcopy(oldkw) if newkw.get('selfaci', False): # selfaci is set in aci_to_kw to True only if the target is self kw['selfaci'] = True newkw.update(kw) for acikw in (oldkw, newkw): acikw.pop('aciname', None) # _make_aci is what is run in aci_add and validates the input. # Do this before we delete the existing ACI. newaci = _make_aci(ldap, None, aciname, newkw) if aci.isequal(newaci): raise errors.EmptyModlist() self.api.Command['aci_del'](aciname, aciprefix=aciprefix) try: result = self.api.Command['aci_add'](aciname, **newkw)['result'] except Exception as e: # ACI could not be added, try to restore the old deleted ACI and # report the ADD error back to user try: self.api.Command['aci_add'](aciname, **oldkw) except Exception: pass raise e if kw.get('raw', False): result = dict(aci=unicode(newaci)) else: result = _aci_to_kw(ldap, newaci) return dict( result=result, value=pkey_to_value(aciname, kw), )
def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) if not options['ipasudoopt'].strip(): raise errors.EmptyModlist() (dn, entry_attrs) = ldap.get_entry(dn, ['ipasudoopt']) try: if options['ipasudoopt'] in entry_attrs['ipasudoopt']: entry_attrs.setdefault('ipasudoopt', []).remove(options['ipasudoopt']) ldap.update_entry(dn, entry_attrs) else: raise errors.AttrValueNotFound(attr='ipasudoopt', value=options['ipasudoopt']) except ValueError, e: pass
def test_remove_empty_location_from_user(self, user): """ Try to "remove" empty location from user """ user.ensure_exists() command = user.make_update_command(dict(l=None)) with raises_exact(errors.EmptyModlist()): command()
class test_config(Declarative): cleanup_commands = [] tests = [ dict( desc='Try to add an unrelated objectclass to ipauserobjectclasses', command=('config_mod', [], dict(addattr=u'ipauserobjectclasses=ipahost')), expected=dict( result=lambda d: 'ipahost' in d['ipauserobjectclasses'], value=None, summary=None, ), ), dict( desc='Remove the unrelated objectclass from ipauserobjectclasses', command=('config_mod', [], dict(delattr=u'ipauserobjectclasses=ipahost')), expected=dict( result=lambda d: 'ipahost' not in d['ipauserobjectclasses'], value=None, summary=None, ), ), dict( desc='Try to remove ipausersearchfields', command= ('config_mod', [], dict( delattr= u'ipausersearchfields=uid,givenname,sn,telephonenumber,ou,title' )), expected=errors.RequirementError(name='usersearch'), ), dict( desc='Add uppercased attribute to ipausersearchfields', command=( 'config_mod', [], dict( ipausersearchfields= u'uid,givenname,sn,telephonenumber,ou,title,Description')), expected=dict( result=lambda d: (d['ipausersearchfields'] == (u'uid,givenname,sn,telephonenumber,ou,title,description', )), value=None, summary=None, ), ), dict( desc='Remove uppercased attribute from ipausersearchfields', command=('config_mod', [], dict(ipausersearchfields= u'uid,givenname,sn,telephonenumber,ou,title', )), expected=dict( result=lambda d: (d['ipausersearchfields'] == (u'uid,givenname,sn,telephonenumber,ou,title', )), value=None, summary=None, ), ), dict( desc= 'Try to set ipaselinuxusermapdefault not in selinux order list', command=('config_mod', [], dict(ipaselinuxusermapdefault=u'unknown_u:s0')), expected=errors.ValidationError( name='ipaselinuxusermapdefault', error='SELinux user map default user not in order list'), ), dict( desc='Try to set invalid ipaselinuxusermapdefault', command=('config_mod', [], dict(ipaselinuxusermapdefault=u'foo')), expected=errors.ValidationError( name='ipaselinuxusermapdefault', error='Invalid MLS value, must match {}, where max level ' '{}'.format(platformconstants.SELINUX_MLS_REGEX, platformconstants.SELINUX_MLS_MAX)), ), dict( desc='Try to set invalid ipaselinuxusermapdefault with setattr', command=('config_mod', [], dict(setattr=u'ipaselinuxusermapdefault=unknown_u:s0')), expected=errors.ValidationError( name='ipaselinuxusermapdefault', error='SELinux user map default user not in order list'), ), dict( desc= 'Try to set ipaselinuxusermaporder without ipaselinuxusermapdefault out of it', command=('config_mod', [], dict(ipaselinuxusermaporder=u'notfound_u:s0')), expected=errors.ValidationError( name='ipaselinuxusermaporder', error='SELinux user map default user not in order list'), ), dict( desc='Try to set invalid ipaselinuxusermaporder', command=('config_mod', [], dict(ipaselinuxusermaporder=u'$')), expected=errors.ValidationError( name='ipaselinuxusermaporder', error='A list of SELinux users delimited by $ expected'), ), dict( desc='Try to set invalid selinux user in ipaselinuxusermaporder', command=('config_mod', [], dict(ipaselinuxusermaporder=u'baduser')), expected=errors.ValidationError( name='ipaselinuxusermaporder', error='SELinux user \'baduser\' is not valid: Invalid MLS ' 'value, must match {}, where max level {}'.format( platformconstants.SELINUX_MLS_REGEX, platformconstants.SELINUX_MLS_MAX)), ), dict( desc='Try to set new selinux order and invalid default user', command=('config_mod', [], dict(ipaselinuxusermaporder=u'foo:s0', ipaselinuxusermapdefault=u'unknown_u:s0')), expected=errors.ValidationError( name='ipaselinuxusermapdefault', error='SELinux user map default user not in order list'), ), dict( desc='Set user auth type', command=('config_mod', [], dict(ipauserauthtype=u'password')), expected=dict( result=lambda d: d['ipauserauthtype'] == (u'password', ), value=None, summary=None, ), ), dict( desc='Check user auth type', command=('config_show', [], {}), expected=dict( result=lambda d: d['ipauserauthtype'] == (u'password', ), value=None, summary=None, ), ), dict( desc='Unset user auth type', command=('config_mod', [], dict(ipauserauthtype=None)), expected=dict( result=lambda d: 'ipauserauthtype' not in d, value=None, summary=None, ), ), dict( desc='Set maximum username length higher than limit of 255', command=('config_mod', [], dict(ipamaxusernamelength=256)), expected=errors.ValidationError(name='maxusername', error='can be at most 255'), ), dict( desc='Set maximum username length equal to limit 255', command=('config_mod', [], dict(ipamaxusernamelength=255)), expected=dict( result=lambda d: d['ipamaxusernamelength'] == (u'255', ), value=None, summary=None, ), ), # Cleanup after previous test - returns max username length to 32 dict( desc='Return maximum username length to default value', command=('config_mod', [], dict(ipamaxusernamelength=32)), expected=dict( result=lambda d: d['ipamaxusernamelength'] == (u'32', ), value=None, summary=None, ), ), dict( desc='Check if domain resolution order does not accept SLD', command=('config_mod', [], { 'ipadomainresolutionorder': u'{domain}:{sl_domain}'.format(domain=domain, sl_domain=sl_domain) }), expected=errors.ValidationError( name=u'ipadomainresolutionorder', error=(u"Invalid domain name '{}': " "single label domains are not supported" ).format(sl_domain), ), ), dict( desc='Set the number of search records to -1 (unlimited)', command=( 'config_mod', [], { 'ipasearchrecordslimit': u'-1', }, ), expected={ 'result': lambda d: d['ipasearchrecordslimit'] == (u'-1', ), 'summary': None, 'value': None, }, ), dict( desc='Set the number of search records to greater than 10', command=( 'config_mod', [], { 'ipasearchrecordslimit': u'100', }, ), expected={ 'result': lambda d: d['ipasearchrecordslimit'] == (u'100', ), 'summary': None, 'value': None, }, ), dict( desc='Set the number of search records to lower than -1', command=( 'config_mod', [], { 'ipasearchrecordslimit': u'-10', }, ), expected=errors.ValidationError( name=u'searchrecordslimit', error=u'must be at least 10', ), ), dict( desc='Set the number of search records to lower than 10', command=( 'config_mod', [], { 'ipasearchrecordslimit': u'1', }, ), expected=errors.ValidationError( name=u'searchrecordslimit', error=u'must be at least 10', ), ), dict( desc='Set the number of search records to zero (unlimited)', command=( 'config_mod', [], { 'ipasearchrecordslimit': u'0', }, ), expected={ 'result': lambda d: d['ipasearchrecordslimit'] == (u'-1', ), 'summary': None, 'value': None, }, ), dict( desc='Set the number of search records back to 100', command=( 'config_mod', [], { 'ipasearchrecordslimit': u'100', }, ), expected={ 'result': lambda d: d['ipasearchrecordslimit'] == (u'100', ), 'summary': None, 'value': None, }, ), dict( desc='Set the value to the already set value, no modifications', command=( 'config_mod', [], { 'ipasearchrecordslimit': u'100', }, ), expected=errors.EmptyModlist(), ), ]
class test_attr(Declarative): cleanup_commands = [ ('user_del', [user1], {}), ] tests = [ dict( desc='Try to add user %r with single-value attribute set via ' 'option and --addattr' % user1, command=('user_add', [user1], dict(givenname=u'Test', sn=u'User1', addattr=u'sn=User2')), expected=errors.OnlyOneValueAllowed(attr='sn'), ), dict( desc='Create %r' % user1, command=('user_add', [user1], dict(givenname=u'Test', sn=u'User1', setattr=None)), expected=dict( value=user1, summary=u'Added user "tuser1"', result=get_user_result(user1, u'Test', u'User1', 'add'), ), ), dict( desc='Change givenname, add mail %r' % user1, command=('user_mod', [user1], dict(setattr=(u'givenname=Finkle', u'[email protected]'))), expected=dict( result=get_user_result( user1, u'Finkle', u'User1', 'mod', mail=[u'*****@*****.**'], ), summary=u'Modified user "tuser1"', value=user1, ), ), dict( desc='Add another mail %r' % user1, command=('user_mod', [user1], dict(addattr=u'[email protected]')), expected=dict( result=get_user_result( user1, u'Finkle', u'User1', 'mod', mail=[u'*****@*****.**', u'*****@*****.**'], ), summary=u'Modified user "tuser1"', value=user1, ), ), dict( desc='Add two phone numbers at once %r' % user1, command=('user_mod', [user1], dict(setattr=u'telephoneNumber=410-555-1212', addattr=u'telephoneNumber=301-555-1212')), expected=dict( result=get_user_result( user1, u'Finkle', u'User1', 'mod', mail=[u'*****@*****.**', u'*****@*****.**'], telephonenumber=[u'410-555-1212', u'301-555-1212'], ), summary=u'Modified user "tuser1"', value=user1, ), ), dict( desc='Go from two phone numbers to one %r' % user1, command=('user_mod', [user1], dict(setattr=u'telephoneNumber=301-555-1212')), expected=dict( result=get_user_result( user1, u'Finkle', u'User1', 'mod', mail=[u'*****@*****.**', u'*****@*****.**'], telephonenumber=[u'301-555-1212'], ), summary=u'Modified user "tuser1"', value=user1, ), ), dict( desc='Add two more phone numbers %r' % user1, command=('user_mod', [user1], dict(addattr=(u'telephoneNumber=703-555-1212', u'telephoneNumber=202-888-9833'))), expected=dict( result=get_user_result( user1, u'Finkle', u'User1', 'mod', mail=[u'*****@*****.**', u'*****@*****.**'], telephonenumber=[ u'301-555-1212', u'703-555-1212', u'202-888-9833' ], ), summary=u'Modified user "tuser1"', value=user1, ), ), dict( desc='Delete one phone number for %r' % user1, command=('user_mod', [user1], dict(delattr=u'telephoneNumber=301-555-1212')), expected=dict( result=get_user_result( user1, u'Finkle', u'User1', 'mod', mail=[u'*****@*****.**', u'*****@*****.**'], telephonenumber=[u'703-555-1212', u'202-888-9833'], ), summary=u'Modified user "tuser1"', value=user1, ), ), dict(desc='Try deleting the number again for %r' % user1, command=('user_mod', [user1], dict(delattr=u'telephoneNumber=301-555-1212')), expected=errors.AttrValueNotFound(attr=u'telephonenumber', value=u'301-555-1212')), dict( desc='Add and delete one phone number for %r' % user1, command=('user_mod', [user1], dict(addattr=u'telephoneNumber=301-555-1212', delattr=u'telephoneNumber=202-888-9833')), expected=dict( result=get_user_result( user1, u'Finkle', u'User1', 'mod', mail=[u'*****@*****.**', u'*****@*****.**'], telephonenumber=[u'703-555-1212', u'301-555-1212'], ), summary=u'Modified user "tuser1"', value=user1, ), ), dict( desc='Add and delete the same phone number for %r' % user1, command=('user_mod', [user1], dict(addattr=(u'telephoneNumber=301-555-1212', u'telephoneNumber=202-888-9833'), delattr=u'telephoneNumber=301-555-1212')), expected=dict( result=get_user_result( user1, u'Finkle', u'User1', 'mod', mail=[u'*****@*****.**', u'*****@*****.**'], telephonenumber=[ u'703-555-1212', u'301-555-1212', u'202-888-9833' ], ), summary=u'Modified user "tuser1"', value=user1, ), ), dict( desc='Set and delete a phone number for %r' % user1, command=('user_mod', [user1], dict(setattr=(u'telephoneNumber=301-555-1212', u'telephoneNumber=202-888-9833'), delattr=u'telephoneNumber=301-555-1212')), expected=dict( result=get_user_result( user1, u'Finkle', u'User1', 'mod', mail=[u'*****@*****.**', u'*****@*****.**'], telephonenumber=[u'202-888-9833'], ), summary=u'Modified user "tuser1"', value=user1, ), ), dict( desc='Try setting givenname to None with setattr in %r' % user1, command=('user_mod', [user1], dict(setattr=(u'givenname='))), expected=errors.RequirementError(name='givenname'), ), dict( desc='Try setting givenname to None with option in %r' % user1, command=('user_mod', [user1], dict(givenname=None)), expected=errors.RequirementError(name='first'), ), dict( desc='Make sure setting givenname works with option in %r' % user1, command=('user_mod', [user1], dict(givenname=u'Fred')), expected=dict( result=get_user_result( user1, u'Fred', u'User1', 'mod', mail=[u'*****@*****.**', u'*****@*****.**'], telephonenumber=[u'202-888-9833'], ), summary=u'Modified user "tuser1"', value=user1, ), ), dict( desc='Make sure setting givenname works with setattr in %r' % user1, command=('user_mod', [user1], dict(setattr=u'givenname=Finkle')), expected=dict( result=get_user_result( user1, u'Finkle', u'User1', 'mod', mail=[u'*****@*****.**', u'*****@*****.**'], telephonenumber=[u'202-888-9833'], ), summary=u'Modified user "tuser1"', value=user1, ), ), dict( desc='Try to "remove" empty location from %r' % user1, command=('user_mod', [user1], dict(l=None)), expected=errors.EmptyModlist(), ), dict( desc='Lock %r using setattr' % user1, command=('user_mod', [user1], dict(setattr=u'nsaccountlock=TrUe')), expected=dict( result=get_user_result( user1, u'Finkle', u'User1', 'mod', mail=[u'*****@*****.**', u'*****@*****.**'], telephonenumber=[u'202-888-9833'], nsaccountlock=True, ), summary=u'Modified user "tuser1"', value=user1, ), ), dict( desc='Unlock %r using addattr&delattr' % user1, command=('user_mod', [user1], dict(addattr=u'nsaccountlock=FaLsE', delattr=u'nsaccountlock=TRUE')), expected=dict( result=get_user_result( user1, u'Finkle', u'User1', 'mod', mail=[u'*****@*****.**', u'*****@*****.**'], telephonenumber=[u'202-888-9833'], ), summary=u'Modified user "tuser1"', value=user1, ), ), dict( desc='Try adding a new group search fields config entry', command=('config_mod', [], dict(addattr=u'ipagroupsearchfields=newattr')), expected=errors.OnlyOneValueAllowed(attr='ipagroupsearchfields'), ), dict( desc='Try adding a new cert subject base config entry', command=('config_mod', [], dict(addattr=u'ipacertificatesubjectbase=0=DOMAIN.COM')), expected=errors.ValidationError( name='ipacertificatesubjectbase', error='attribute is not configurable'), ), dict( desc='Try deleting a required config entry', command=('config_mod', [], dict(delattr=u'ipasearchrecordslimit=100')), expected=errors.RequirementError(name='ipasearchrecordslimit'), ), dict( desc='Try setting nonexistent attribute', command=('config_mod', [], dict(setattr=u'invalid_attr=false')), expected=errors.ObjectclassViolation( info='attribute "invalid_attr" not allowed'), ), dict( desc='Try setting out-of-range krbpwdmaxfailure', command=('pwpolicy_mod', [], dict(setattr=u'krbpwdmaxfailure=-1')), expected=errors.ValidationError(name='krbpwdmaxfailure', error='must be at least 0'), ), dict( desc='Try setting out-of-range maxfail', command=('pwpolicy_mod', [], dict(krbpwdmaxfailure=u'-1')), expected=errors.ValidationError(name='maxfail', error='must be at least 0'), ), dict( desc='Try setting non-numeric krbpwdmaxfailure', command=('pwpolicy_mod', [], dict(setattr=u'krbpwdmaxfailure=abc')), expected=errors.ConversionError(name='krbpwdmaxfailure', error='must be an integer'), ), dict( desc='Try setting non-numeric maxfail', command=('pwpolicy_mod', [], dict(krbpwdmaxfailure=u'abc')), expected=errors.ConversionError(name='maxfail', error='must be an integer'), ), dict( desc='Try deleting bogus attribute', command=('config_mod', [], dict(delattr=u'bogusattribute=xyz')), expected=errors.ValidationError( name='bogusattribute', error='No such attribute on this entry'), ), dict( desc='Try deleting empty attribute', command=('config_mod', [], dict(delattr=u'ipaCustomFields=See Also,seealso,false')), expected=errors.ValidationError( name='ipacustomfields', error='No such attribute on this entry'), ), dict( desc='Set and delete one value, plus try deleting a missing one', command=('config_mod', [], dict(delattr=[ u'ipaCustomFields=See Also,seealso,false', u'ipaCustomFields=Country,c,false' ], addattr=u'ipaCustomFields=See Also,seealso,false')), expected=errors.AttrValueNotFound(attr='ipacustomfields', value='Country,c,false'), ), dict( desc='Try to delete an operational attribute with --delattr', command=('config_mod', [], dict(delattr=u'creatorsName=cn=directory manager')), expected=errors.DatabaseError( desc='Server is unwilling to perform', info=''), ), ]