From 8e49d6db6973078396b869ab4ed59c565d7010a9 Mon Sep 17 00:00:00 2001 From: Mark Reynolds Date: Dec 08 2015 01:02:35 +0000 Subject: Ticket 48370 - The 'eq' index does not get updated properly when deleting and re-adding attributes in the same modify operation Bug Description: If you delete several values of the same attribute, and add at least one of them back in the same operation, the equality index does not get updated. Fix Description: Modify the logic of the index code to update the index if at least one of the values in the entry changes. Also did pep8 cleanup of create_test.py https://fedorahosted.org/389/ticket/48370 Reviewed by: wibrown(Thanks!) (cherry picked from commit 63b80b5c31ebda51445c662903a28e2a79ebe60a) (cherry picked from commit 5cd8f73205007ecbd44ae2fbfb5bcdf7e39c3d6e) --- diff --git a/dirsrvtests/tickets/ticket48370_test.py b/dirsrvtests/tickets/ticket48370_test.py new file mode 100644 index 0000000..f5b1f47 --- /dev/null +++ b/dirsrvtests/tickets/ticket48370_test.py @@ -0,0 +1,236 @@ +import os +import ldap +import logging +import pytest +from lib389 import DirSrv, Entry +from lib389._constants import * +from lib389.properties import * +from lib389.tasks import * +from lib389.utils import * + +logging.getLogger(__name__).setLevel(logging.DEBUG) +log = logging.getLogger(__name__) + +installation1_prefix = None + + +class TopologyStandalone(object): + def __init__(self, standalone): + standalone.open() + self.standalone = standalone + + +@pytest.fixture(scope="module") +def topology(request): + global installation1_prefix + if installation1_prefix: + args_instance[SER_DEPLOYED_DIR] = installation1_prefix + + # Creating standalone instance ... + standalone = DirSrv(verbose=False) + args_instance[SER_HOST] = HOST_STANDALONE + args_instance[SER_PORT] = PORT_STANDALONE + args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE + args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX + args_standalone = args_instance.copy() + standalone.allocate(args_standalone) + instance_standalone = standalone.exists() + if instance_standalone: + standalone.delete() + standalone.create() + standalone.open() + + # Delete each instance in the end + def fin(): + standalone.delete() + request.addfinalizer(fin) + + # Clear out the tmp dir + standalone.clearTmpDir(__file__) + + return TopologyStandalone(standalone) + + +def test_ticket48370(topology): + """ + Deleting attirbute values and readding a value does not properly update + the pres index. The values are not actually deleted from the index + """ + + DN = 'uid=user0099,' + DEFAULT_SUFFIX + + # + # Add an entry + # + topology.standalone.add_s(Entry((DN, { + 'objectclass': ['top', 'person', + 'organizationalPerson', + 'inetorgperson', + 'posixAccount'], + 'givenname': 'test', + 'sn': 'user', + 'loginshell': '/bin/bash', + 'uidNumber': '10099', + 'gidNumber': '10099', + 'gecos': 'Test User', + 'mail': ['user0099@dev.null', + 'alias@dev.null', + 'user0099@redhat.com'], + 'cn': 'Test User', + 'homeDirectory': '/home/user0099', + 'uid': 'admin2', + 'userpassword': 'password'}))) + + # + # Perform modify (delete & add mail attributes) + # + try: + topology.standalone.modify_s(DN, [(ldap.MOD_DELETE, + 'mail', + 'user0099@dev.null'), + (ldap.MOD_DELETE, + 'mail', + 'alias@dev.null'), + (ldap.MOD_ADD, + 'mail', 'user0099@dev.null')]) + except ldap.LDAPError as e: + log.fatal('Failedto modify user: ' + str(e)) + assert False + + # + # Search using deleted attribute value- no entries should be returned + # + try: + entry = topology.standalone.search_s(DEFAULT_SUFFIX, + ldap.SCOPE_SUBTREE, + 'mail=alias@dev.null') + if entry: + log.fatal('Entry incorrectly returned') + assert False + except ldap.LDAPError as e: + log.fatal('Failed to search for user: ' + str(e)) + assert False + + # + # Search using existing attribute value - the entry should be returned + # + try: + entry = topology.standalone.search_s(DEFAULT_SUFFIX, + ldap.SCOPE_SUBTREE, + 'mail=user0099@dev.null') + if entry is None: + log.fatal('Entry not found, but it should have been') + assert False + except ldap.LDAPError as e: + log.fatal('Failed to search for user: ' + str(e)) + assert False + + # + # Delete the last values + # + try: + topology.standalone.modify_s(DN, [(ldap.MOD_DELETE, + 'mail', + 'user0099@dev.null'), + (ldap.MOD_DELETE, + 'mail', + 'user0099@redhat.com') + ]) + except ldap.LDAPError as e: + log.fatal('Failed to modify user: ' + str(e)) + assert False + + # + # Search using deleted attribute value - no entries should be returned + # + try: + entry = topology.standalone.search_s(DEFAULT_SUFFIX, + ldap.SCOPE_SUBTREE, + 'mail=user0099@redhat.com') + if entry: + log.fatal('Entry incorrectly returned') + assert False + except ldap.LDAPError as e: + log.fatal('Failed to search for user: ' + str(e)) + assert False + + # + # Make sure presence index is correctly updated - no entries should be + # returned + # + try: + entry = topology.standalone.search_s(DEFAULT_SUFFIX, + ldap.SCOPE_SUBTREE, + 'mail=*') + if entry: + log.fatal('Entry incorrectly returned') + assert False + except ldap.LDAPError as e: + log.fatal('Failed to search for user: ' + str(e)) + assert False + + # + # Now add the attributes back, and lets run a different set of tests with + # a different number of attributes + # + try: + topology.standalone.modify_s(DN, [(ldap.MOD_ADD, + 'mail', + ['user0099@dev.null', + 'alias@dev.null'])]) + except ldap.LDAPError as e: + log.fatal('Failedto modify user: ' + str(e)) + assert False + + # + # Remove and readd some attibutes + # + try: + topology.standalone.modify_s(DN, [(ldap.MOD_DELETE, + 'mail', + 'alias@dev.null'), + (ldap.MOD_DELETE, + 'mail', + 'user0099@dev.null'), + (ldap.MOD_ADD, + 'mail', 'user0099@dev.null')]) + except ldap.LDAPError as e: + log.fatal('Failedto modify user: ' + str(e)) + assert False + + # + # Search using deleted attribute value - no entries should be returned + # + try: + entry = topology.standalone.search_s(DEFAULT_SUFFIX, + ldap.SCOPE_SUBTREE, + 'mail=alias@dev.null') + if entry: + log.fatal('Entry incorrectly returned') + assert False + except ldap.LDAPError as e: + log.fatal('Failed to search for user: ' + str(e)) + assert False + + # + # Search using existing attribute value - the entry should be returned + # + try: + entry = topology.standalone.search_s(DEFAULT_SUFFIX, + ldap.SCOPE_SUBTREE, + 'mail=user0099@dev.null') + if entry is None: + log.fatal('Entry not found, but it should have been') + assert False + except ldap.LDAPError as e: + log.fatal('Failed to search for user: ' + str(e)) + assert False + + log.info('Test PASSED') + + +if __name__ == '__main__': + # Run isolated + # -s for DEBUG mode + CURRENT_FILE = os.path.realpath(__file__) + pytest.main("-s %s" % CURRENT_FILE) diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c index ffeedef..ff59875 100644 --- a/ldap/servers/slapd/back-ldbm/index.c +++ b/ldap/servers/slapd/back-ldbm/index.c @@ -747,31 +747,24 @@ index_add_mods( flags = BE_INDEX_DEL|BE_INDEX_PRESENCE|BE_INDEX_EQUALITY; } else { flags = BE_INDEX_DEL; - - /* If the same value doesn't exist in a subtype, set - * BE_INDEX_EQUALITY flag so the equality index is - * removed. - */ curr_attr = NULL; slapi_entry_attr_find(olde->ep_entry, - mods[i]->mod_type, &curr_attr); + mods[i]->mod_type, + &curr_attr); if (curr_attr) { - int found = 0; for (j = 0; mods_valueArray[j] != NULL; j++ ) { - if ( slapi_valueset_find(curr_attr, all_vals, mods_valueArray[j])) { - /* The same value found in evals. - * We don't touch the equality index. */ - found = 1; + if ( !slapi_valueset_find(curr_attr, all_vals, mods_valueArray[j]) ) { + /* + * If the mod del value is not found in all_vals + * we need to update the equality index as the + * final value(s) have changed + */ + if (!(flags & BE_INDEX_EQUALITY)) { + flags |= BE_INDEX_EQUALITY; + } break; } } - /* - * to-be-deleted curr_attr does not exist in the - * new value set evals. So, we can remove it. - */ - if (!found && !(flags & BE_INDEX_EQUALITY)) { - flags |= BE_INDEX_EQUALITY; - } } }