Blob Blame Raw
From 4a52c95b2f7815c15efd84daf57ced08e7855cc2 Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Mon, 7 Dec 2015 16:45:06 -0500
Subject: [PATCH 77/78] 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 4a53592ec89d288f182c509dc7fcc104d8cbc4a8)
---
 dirsrvtests/create_test.py              | 393 +++++++++++++++++++-------------
 dirsrvtests/tickets/ticket48370_test.py | 236 +++++++++++++++++++
 ldap/servers/slapd/back-ldbm/index.c    |  29 +--
 3 files changed, 480 insertions(+), 178 deletions(-)
 create mode 100644 dirsrvtests/tickets/ticket48370_test.py

diff --git a/dirsrvtests/create_test.py b/dirsrvtests/create_test.py
index 941e922..5293991 100755
--- a/dirsrvtests/create_test.py
+++ b/dirsrvtests/create_test.py
@@ -22,14 +22,16 @@ import optparse
 
 
 def displayUsage():
-    print ('\nUsage:\ncreate_ticket.py -t|--ticket <ticket number> -s|--suite <suite name> ' +
-           '[ i|--instances <number of standalone instances> [ -m|--masters <number of masters> ' +
-           '-h|--hubs <number of hubs> -c|--consumers <number of consumers> ] ' +
-           '-o|--outputfile ]\n')
-    print ('If only "-t" is provided then a single standalone instance is created.  ' +
-           'Or you can create a test suite script using "-s|--suite" instead of using "-t|--ticket".' +
-           'The "-i" option can add mulitple standalone instances(maximum 10).  ' +
-           'However, you can not mix "-i" with the replication options(-m, -h , -c).  ' +
+    print ('\nUsage:\ncreate_ticket.py -t|--ticket <ticket number> ' +
+           '-s|--suite <suite name> ' +
+           '[ i|--instances <number of standalone instances> ' +
+           '[ -m|--masters <number of masters> -h|--hubs <number of hubs> ' +
+           '-c|--consumers <number of consumers> ] -o|--outputfile ]\n')
+    print ('If only "-t" is provided then a single standalone instance is ' +
+           'created.  Or you can create a test suite script using ' +
+           '"-s|--suite" instead of using "-t|--ticket".  The "-i" option ' +
+           'can add mulitple standalone instances(maximum 10).  However, you' +
+           ' can not mix "-i" with the replication options(-m, -h , -c).  ' +
            'There is a maximum of 10 masters, 10 hubs, and 10 consumers.')
     exit(1)
 
@@ -59,34 +61,47 @@ if len(sys.argv) > 0:
         displayUsage()
 
     if args.ticket and args.suite:
-        print 'You must choose either "-t|--ticket" or "-s|--suite", but not both.'
+        print('You must choose either "-t|--ticket" or "-s|--suite", ' +
+              'but not both.')
         displayUsage()
 
     if int(args.masters) == 0:
         if int(args.hubs) > 0 or int(args.consumers) > 0:
-            print 'You must use "-m|--masters" if you want to have hubs and/or consumers'
+            print('You must use "-m|--masters" if you want to have hubs ' +
+                  'and/or consumers')
             displayUsage()
 
-    if not args.masters.isdigit() or int(args.masters) > 10 or int(args.masters) < 0:
-        print 'Invalid value for "--masters", it must be a number and it can not be greater than 10'
+    if not args.masters.isdigit() or \
+           int(args.masters) > 10 or \
+           int(args.masters) < 0:
+        print('Invalid value for "--masters", it must be a number and it can' +
+              ' not be greater than 10')
         displayUsage()
 
     if not args.hubs.isdigit() or int(args.hubs) > 10 or int(args.hubs) < 0:
-        print 'Invalid value for "--hubs", it must be a number and it can not be greater than 10'
+        print('Invalid value for "--hubs", it must be a number and it can ' +
+              'not be greater than 10')
         displayUsage()
 
-    if not args.consumers.isdigit() or int(args.consumers) > 10 or int(args.consumers) < 0:
-        print 'Invalid value for "--consumers", it must be a number and it can not be greater than 10'
+    if not args.consumers.isdigit() or \
+           int(args.consumers) > 10 or \
+           int(args.consumers) < 0:
+        print('Invalid value for "--consumers", it must be a number and it ' +
+              'can not be greater than 10')
         displayUsage()
 
     if args.inst:
-        if not args.inst.isdigit() or int(args.inst) > 10 or int(args.inst) < 1:
-            print ('Invalid value for "--instances", it must be a number greater than 0 ' +
-                   'and not greater than 10')
+        if not args.inst.isdigit() or \
+               int(args.inst) > 10 or \
+               int(args.inst) < 1:
+            print('Invalid value for "--instances", it must be a number ' +
+                  'greater than 0 and not greater than 10')
             displayUsage()
         if int(args.inst) > 0:
-            if int(args.masters) > 0 or int(args.hubs) > 0 or int(args.consumers) > 0:
-                print 'You can not mix "--instances" with replication.'
+            if int(args.masters) > 0 or \
+               int(args.hubs) > 0 or \
+               int(args.consumers) > 0:
+                print('You can not mix "--instances" with replication.')
                 displayUsage()
 
     # Extract usable values
@@ -120,9 +135,11 @@ if len(sys.argv) > 0:
     #
     # Write the imports
     #
-    TEST.write('import os\nimport sys\nimport time\nimport ldap\nimport logging\nimport pytest\n')
-    TEST.write('from lib389 import DirSrv, Entry, tools, tasks\nfrom lib389.tools import DirSrvTools\n' +
-               'from lib389._constants import *\nfrom lib389.properties import *\n' +
+    TEST.write('import os\nimport sys\nimport time\nimport ldap\n' +
+               'import logging\nimport pytest\n')
+    TEST.write('from lib389 import DirSrv, Entry, tools, tasks\nfrom ' +
+               'lib389.tools import DirSrvTools\nfrom lib389._constants ' +
+               'import *\nfrom lib389.properties import *\n' +
                'from lib389.tasks import *\nfrom lib389.utils import *\n\n')
 
     #
@@ -154,13 +171,16 @@ if len(sys.argv) > 0:
 
         for idx in range(masters):
             TEST.write('        master' + str(idx + 1) + '.open()\n')
-            TEST.write('        self.master' + str(idx + 1) + ' = master' + str(idx + 1) + '\n')
+            TEST.write('        self.master' + str(idx + 1) + ' = master' +
+                       str(idx + 1) + '\n')
         for idx in range(hubs):
             TEST.write('        hub' + str(idx + 1) + '.open()\n')
-            TEST.write('        self.hub' + str(idx + 1) + ' = hub' + str(idx + 1) + '\n')
+            TEST.write('        self.hub' + str(idx + 1) + ' = hub' +
+                       str(idx + 1) + '\n')
         for idx in range(consumers):
             TEST.write('        consumer' + str(idx + 1) + '.open()\n')
-            TEST.write('        self.consumer' + str(idx + 1) + ' = consumer' + str(idx + 1) + '\n')
+            TEST.write('        self.consumer' + str(idx + 1) + ' = consumer' +
+                       str(idx + 1) + '\n')
         TEST.write('\n\n')
     else:
         #
@@ -184,7 +204,8 @@ if len(sys.argv) > 0:
             else:
                 idx = str(idx)
             TEST.write('        standalone' + idx + '.open()\n')
-            TEST.write('        self.standalone' + idx + ' = standalone' + idx + '\n')
+            TEST.write('        self.standalone' + idx + ' = standalone' +
+                       idx + '\n')
         TEST.write('\n\n')
 
     #
@@ -194,7 +215,8 @@ if len(sys.argv) > 0:
     TEST.write('def topology(request):\n')
     TEST.write('    global installation1_prefix\n')
     TEST.write('    if installation1_prefix:\n')
-    TEST.write('        args_instance[SER_DEPLOYED_DIR] = installation1_prefix\n\n')
+    TEST.write('        args_instance[SER_DEPLOYED_DIR] = ' +
+               'installation1_prefix\n\n')
 
     if repl_deployment:
         #
@@ -204,20 +226,25 @@ if len(sys.argv) > 0:
             idx = str(idx + 1)
             TEST.write('    # Creating master ' + idx + '...\n')
             TEST.write('    master' + idx + ' = DirSrv(verbose=False)\n')
-            TEST.write('    args_instance[SER_HOST] = HOST_MASTER_' + idx + '\n')
-            TEST.write('    args_instance[SER_PORT] = PORT_MASTER_' + idx + '\n')
-            TEST.write('    args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_' + idx + '\n')
-            TEST.write('    args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX\n')
+            TEST.write('    args_instance[SER_HOST] = HOST_MASTER_' + idx +
+                       '\n')
+            TEST.write('    args_instance[SER_PORT] = PORT_MASTER_' + idx +
+                       '\n')
+            TEST.write('    args_instance[SER_SERVERID_PROP] = ' +
+                       'SERVERID_MASTER_' + idx + '\n')
+            TEST.write('    args_instance[SER_CREATION_SUFFIX] = ' +
+                       'DEFAULT_SUFFIX\n')
             TEST.write('    args_master = args_instance.copy()\n')
             TEST.write('    master' + idx + '.allocate(args_master)\n')
-            TEST.write('    instance_master' + idx + ' = master' + idx + '.exists()\n')
+            TEST.write('    instance_master' + idx + ' = master' + idx +
+                       '.exists()\n')
             TEST.write('    if instance_master' + idx + ':\n')
             TEST.write('        master' + idx + '.delete()\n')
             TEST.write('    master' + idx + '.create()\n')
             TEST.write('    master' + idx + '.open()\n')
-            TEST.write('    master' + idx + '.replica.enableReplication(suffix=SUFFIX, ' +
-                                            'role=REPLICAROLE_MASTER, ' +
-                                            'replicaId=REPLICAID_MASTER_' + idx + ')\n\n')
+            TEST.write('    master' + idx + '.replica.enableReplication' +
+                       '(suffix=SUFFIX, role=REPLICAROLE_MASTER, ' +
+                       'replicaId=REPLICAID_MASTER_' + idx + ')\n\n')
 
         for idx in range(hubs):
             idx = str(idx + 1)
@@ -225,37 +252,45 @@ if len(sys.argv) > 0:
             TEST.write('    hub' + idx + ' = DirSrv(verbose=False)\n')
             TEST.write('    args_instance[SER_HOST] = HOST_HUB_' + idx + '\n')
             TEST.write('    args_instance[SER_PORT] = PORT_HUB_' + idx + '\n')
-            TEST.write('    args_instance[SER_SERVERID_PROP] = SERVERID_HUB_' + idx + '\n')
-            TEST.write('    args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX\n')
+            TEST.write('    args_instance[SER_SERVERID_PROP] = SERVERID_HUB_' +
+                       idx + '\n')
+            TEST.write('    args_instance[SER_CREATION_SUFFIX] = ' +
+                       'DEFAULT_SUFFIX\n')
             TEST.write('    args_hub = args_instance.copy()\n')
             TEST.write('    hub' + idx + '.allocate(args_hub)\n')
-            TEST.write('    instance_hub' + idx + ' = hub' + idx + '.exists()\n')
+            TEST.write('    instance_hub' + idx + ' = hub' + idx +
+                       '.exists()\n')
             TEST.write('    if instance_hub' + idx + ':\n')
             TEST.write('        hub' + idx + '.delete()\n')
             TEST.write('    hub' + idx + '.create()\n')
             TEST.write('    hub' + idx + '.open()\n')
-            TEST.write('    hub' + idx + '.replica.enableReplication(suffix=SUFFIX, ' +
-                                            'role=REPLICAROLE_HUB, ' +
-                                            'replicaId=REPLICAID_HUB_' + idx + ')\n\n')
+            TEST.write('    hub' + idx + '.replica.enableReplication' +
+                       '(suffix=SUFFIX, role=REPLICAROLE_HUB, ' +
+                       'replicaId=REPLICAID_HUB_' + idx + ')\n\n')
 
         for idx in range(consumers):
             idx = str(idx + 1)
             TEST.write('    # Creating consumer ' + idx + '...\n')
             TEST.write('    consumer' + idx + ' = DirSrv(verbose=False)\n')
-            TEST.write('    args_instance[SER_HOST] = HOST_CONSUMER_' + idx + '\n')
-            TEST.write('    args_instance[SER_PORT] = PORT_CONSUMER_' + idx + '\n')
-            TEST.write('    args_instance[SER_SERVERID_PROP] = SERVERID_CONSUMER_' + idx + '\n')
-            TEST.write('    args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX\n')
+            TEST.write('    args_instance[SER_HOST] = HOST_CONSUMER_' + idx +
+                       '\n')
+            TEST.write('    args_instance[SER_PORT] = PORT_CONSUMER_' + idx +
+                       '\n')
+            TEST.write('    args_instance[SER_SERVERID_PROP] = ' +
+                       'SERVERID_CONSUMER_' + idx + '\n')
+            TEST.write('    args_instance[SER_CREATION_SUFFIX] = ' +
+                       'DEFAULT_SUFFIX\n')
             TEST.write('    args_consumer = args_instance.copy()\n')
             TEST.write('    consumer' + idx + '.allocate(args_consumer)\n')
-            TEST.write('    instance_consumer' + idx + ' = consumer' + idx + '.exists()\n')
+            TEST.write('    instance_consumer' + idx + ' = consumer' + idx +
+                       '.exists()\n')
             TEST.write('    if instance_consumer' + idx + ':\n')
             TEST.write('        consumer' + idx + '.delete()\n')
             TEST.write('    consumer' + idx + '.create()\n')
             TEST.write('    consumer' + idx + '.open()\n')
-            TEST.write('    consumer' + idx + '.replica.enableReplication(suffix=SUFFIX, ' +
-                                            'role=REPLICAROLE_CONSUMER, ' +
-                                            'replicaId=CONSUMER_REPLICAID)\n\n')
+            TEST.write('    consumer' + idx + '.replica.enableReplication' +
+                       '(suffix=SUFFIX, role=REPLICAROLE_CONSUMER, ' +
+                       'replicaId=CONSUMER_REPLICAID)\n\n')
 
         #
         # Create the master agreements
@@ -274,39 +309,61 @@ if len(sys.argv) > 0:
                 if master_idx == idx:
                     # skip ourselves
                     continue
-                TEST.write('    # Creating agreement from master ' + str(master_idx) + ' to master ' + str(idx) + '\n')
-                TEST.write("    properties = {RA_NAME:      r'meTo_$host:$port',\n")
-                TEST.write("                  RA_BINDDN:    defaultProperties[REPLICATION_BIND_DN],\n")
-                TEST.write("                  RA_BINDPW:    defaultProperties[REPLICATION_BIND_PW],\n")
-                TEST.write("                  RA_METHOD:    defaultProperties[REPLICATION_BIND_METHOD],\n")
-                TEST.write("                  RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}\n")
-                TEST.write('    m' + str(master_idx) + '_m' + str(idx) + '_agmt = master' + str(master_idx) +
+                TEST.write('    # Creating agreement from master ' +
+                           str(master_idx) + ' to master ' + str(idx) + '\n')
+                TEST.write("    properties = {RA_NAME:      " +
+                           "r'meTo_$host:$port',\n")
+                TEST.write("                  RA_BINDDN:    " +
+                           "defaultProperties[REPLICATION_BIND_DN],\n")
+                TEST.write("                  RA_BINDPW:    " +
+                           "defaultProperties[REPLICATION_BIND_PW],\n")
+                TEST.write("                  RA_METHOD:    " +
+                           "defaultProperties[REPLICATION_BIND_METHOD],\n")
+                TEST.write("                  RA_TRANSPORT_PROT: " +
+                           "defaultProperties[REPLICATION_TRANSPORT]}\n")
+                TEST.write('    m' + str(master_idx) + '_m' + str(idx) +
+                           '_agmt = master' + str(master_idx) +
                             '.agreement.create(suffix=SUFFIX, host=master' +
-                            str(idx) + '.host, port=master' + str(idx) + '.port, properties=properties)\n')
-                TEST.write('    if not m' + str(master_idx) + '_m' + str(idx) + '_agmt:\n')
-                TEST.write('        log.fatal("Fail to create a master -> master replica agreement")\n')
+                            str(idx) + '.host, port=master' + str(idx) +
+                            '.port, properties=properties)\n')
+                TEST.write('    if not m' + str(master_idx) + '_m' + str(idx) +
+                           '_agmt:\n')
+                TEST.write('        log.fatal("Fail to create a master -> ' +
+                           'master replica agreement")\n')
                 TEST.write('        sys.exit(1)\n')
-                TEST.write('    log.debug("%s created" % m' + str(master_idx) + '_m' + str(idx) + '_agmt)\n\n')
+                TEST.write('    log.debug("%s created" % m' + str(master_idx) +
+                           '_m' + str(idx) + '_agmt)\n\n')
                 agmt_count += 1
 
             for idx in range(hubs):
                 idx += 1
                 #
-                # Create agreements from each master to each hub (master -> hub)
+                # Create agmts from each master to each hub (master -> hub)
                 #
-                TEST.write('    # Creating agreement from master ' + str(master_idx) + ' to hub ' + str(idx) + '\n')
-                TEST.write("    properties = {RA_NAME:      r'meTo_$host:$port',\n")
-                TEST.write("                  RA_BINDDN:    defaultProperties[REPLICATION_BIND_DN],\n")
-                TEST.write("                  RA_BINDPW:    defaultProperties[REPLICATION_BIND_PW],\n")
-                TEST.write("                  RA_METHOD:    defaultProperties[REPLICATION_BIND_METHOD],\n")
-                TEST.write("                  RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}\n")
-                TEST.write('    m' + str(master_idx) + '_h' + str(idx) + '_agmt = master' + str(master_idx) +
-                            '.agreement.create(suffix=SUFFIX, host=hub' +
-                            str(idx) + '.host, port=hub' + str(idx) + '.port, properties=properties)\n')
-                TEST.write('    if not m' + str(master_idx) + '_h' + str(idx) + '_agmt:\n')
-                TEST.write('        log.fatal("Fail to create a master -> hub replica agreement")\n')
+                TEST.write('    # Creating agreement from master ' +
+                           str(master_idx) + ' to hub ' + str(idx) + '\n')
+                TEST.write("    properties = {RA_NAME:      " +
+                           "r'meTo_$host:$port',\n")
+                TEST.write("                  RA_BINDDN:    " +
+                           "defaultProperties[REPLICATION_BIND_DN],\n")
+                TEST.write("                  RA_BINDPW:    " +
+                           "defaultProperties[REPLICATION_BIND_PW],\n")
+                TEST.write("                  RA_METHOD:    " +
+                           "defaultProperties[REPLICATION_BIND_METHOD],\n")
+                TEST.write("                  RA_TRANSPORT_PROT: " +
+                           "defaultProperties[REPLICATION_TRANSPORT]}\n")
+                TEST.write('    m' + str(master_idx) + '_h' + str(idx) +
+                           '_agmt = master' + str(master_idx) +
+                           '.agreement.create(suffix=SUFFIX, host=hub' +
+                           str(idx) + '.host, port=hub' + str(idx) +
+                           '.port, properties=properties)\n')
+                TEST.write('    if not m' + str(master_idx) + '_h' + str(idx) +
+                           '_agmt:\n')
+                TEST.write('        log.fatal("Fail to create a master -> ' +
+                           'hub replica agreement")\n')
                 TEST.write('        sys.exit(1)\n')
-                TEST.write('    log.debug("%s created" % m' + str(master_idx) + '_h' + str(idx) + '_agmt)\n\n')
+                TEST.write('    log.debug("%s created" % m' + str(master_idx) +
+                           '_h' + str(idx) + '_agmt)\n\n')
                 agmt_count += 1
 
         #
@@ -322,24 +379,35 @@ if len(sys.argv) > 0:
                 #
                 # Create agreements from each hub to each consumer
                 #
-                TEST.write('    # Creating agreement from hub ' + str(hub_idx) + ' to consumer ' + str(idx) + '\n')
-                TEST.write("    properties = {RA_NAME:      r'meTo_$host:$port',\n")
-                TEST.write("                  RA_BINDDN:    defaultProperties[REPLICATION_BIND_DN],\n")
-                TEST.write("                  RA_BINDPW:    defaultProperties[REPLICATION_BIND_PW],\n")
-                TEST.write("                  RA_METHOD:    defaultProperties[REPLICATION_BIND_METHOD],\n")
-                TEST.write("                  RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}\n")
-                TEST.write('    h' + str(hub_idx) + '_c' + str(idx) + '_agmt = hub' +
-                            str(hub_idx) + '.agreement.create(suffix=SUFFIX, host=consumer' +
-                            str(idx) + '.host, port=consumer' + str(idx) + '.port, properties=properties)\n')
-                TEST.write('    if not h' + str(hub_idx) + '_c' + str(idx) + '_agmt:\n')
-                TEST.write('        log.fatal("Fail to create a hub -> consumer replica agreement")\n')
+                TEST.write('    # Creating agreement from hub ' + str(hub_idx)
+                           + ' to consumer ' + str(idx) + '\n')
+                TEST.write("    properties = {RA_NAME:      " +
+                           "r'meTo_$host:$port',\n")
+                TEST.write("                  RA_BINDDN:    " +
+                           "defaultProperties[REPLICATION_BIND_DN],\n")
+                TEST.write("                  RA_BINDPW:    " +
+                           "defaultProperties[REPLICATION_BIND_PW],\n")
+                TEST.write("                  RA_METHOD:    " +
+                           "defaultProperties[REPLICATION_BIND_METHOD],\n")
+                TEST.write("                  RA_TRANSPORT_PROT: " +
+                           "defaultProperties[REPLICATION_TRANSPORT]}\n")
+                TEST.write('    h' + str(hub_idx) + '_c' + str(idx) +
+                           '_agmt = hub' + str(hub_idx) +
+                           '.agreement.create(suffix=SUFFIX, host=consumer' +
+                           str(idx) + '.host, port=consumer' + str(idx) +
+                           '.port, properties=properties)\n')
+                TEST.write('    if not h' + str(hub_idx) + '_c' + str(idx) +
+                           '_agmt:\n')
+                TEST.write('        log.fatal("Fail to create a hub -> ' +
+                           'consumer replica agreement")\n')
                 TEST.write('        sys.exit(1)\n')
-                TEST.write('    log.debug("%s created" % h' + str(hub_idx) + '_c' + str(idx) + '_agmt)\n\n')
+                TEST.write('    log.debug("%s created" % h' + str(hub_idx) +
+                           '_c' + str(idx) + '_agmt)\n\n')
                 agmt_count += 1
 
         if hubs == 0:
             #
-            # No Hubs, see if there are any consumers to create agreements to...
+            # No Hubs, see if there are any consumers to create agreements to
             #
             for idx in range(masters):
                 master_idx = idx + 1
@@ -351,27 +419,40 @@ if len(sys.argv) > 0:
                     #
                     # Create agreements from each master to each consumer
                     #
-                    TEST.write('    # Creating agreement from master ' + str(master_idx) +
-                               ' to consumer ' + str(idx) + '\n')
-                    TEST.write("    properties = {RA_NAME:      r'meTo_$host:$port',\n")
-                    TEST.write("                  RA_BINDDN:    defaultProperties[REPLICATION_BIND_DN],\n")
-                    TEST.write("                  RA_BINDPW:    defaultProperties[REPLICATION_BIND_PW],\n")
-                    TEST.write("                  RA_METHOD:    defaultProperties[REPLICATION_BIND_METHOD],\n")
-                    TEST.write("                  RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}\n")
-                    TEST.write('    m' + str(master_idx) + '_c' + str(idx) + '_agmt = master' + str(master_idx) +
-                                '.agreement.create(suffix=SUFFIX, host=consumer' +
-                                str(idx) + '.host, port=consumer' + str(idx) +
-                                '.port, properties=properties)\n')
-                    TEST.write('    if not m' + str(master_idx) + '_c' + str(idx) + '_agmt:\n')
-                    TEST.write('        log.fatal("Fail to create a hub -> consumer replica agreement")\n')
+                    TEST.write('    # Creating agreement from master ' +
+                               str(master_idx) + ' to consumer ' + str(idx) +
+                               '\n')
+                    TEST.write("    properties = {RA_NAME:      " +
+                               "r'meTo_$host:$port',\n")
+                    TEST.write("                  RA_BINDDN:    " +
+                               "defaultProperties[REPLICATION_BIND_DN],\n")
+                    TEST.write("                  RA_BINDPW:    " +
+                               "defaultProperties[REPLICATION_BIND_PW],\n")
+                    TEST.write("                  RA_METHOD:    " +
+                               "defaultProperties[REPLICATION_BIND_METHOD],\n")
+                    TEST.write("                  RA_TRANSPORT_PROT: " +
+                               "defaultProperties[REPLICATION_TRANSPORT]}\n")
+                    TEST.write('    m' + str(master_idx) + '_c' + str(idx) +
+                               '_agmt = master' + str(master_idx) +
+                               '.agreement.create(suffix=SUFFIX, ' +
+                               'host=consumer' + str(idx) +
+                               '.host, port=consumer' + str(idx) +
+                               '.port, properties=properties)\n')
+                    TEST.write('    if not m' + str(master_idx) + '_c' +
+                               str(idx) + '_agmt:\n')
+                    TEST.write('        log.fatal("Fail to create a hub -> ' +
+                               'consumer replica agreement")\n')
                     TEST.write('        sys.exit(1)\n')
-                    TEST.write('    log.debug("%s created" % m' + str(master_idx) + '_c' + str(idx) + '_agmt)\n\n')
+                    TEST.write('    log.debug("%s created" % m' +
+                               str(master_idx) + '_c' + str(idx) +
+                               '_agmt)\n\n')
                     agmt_count += 1
 
         #
         # Add sleep that allows all the agreemnts to get situated
         #
-        TEST.write('    # Allow the replicas to get situated with the new agreements...\n')
+        TEST.write('    # Allow the replicas to get situated with the new ' +
+                   'agreements...\n')
         TEST.write('    time.sleep(5)\n\n')
 
         #
@@ -388,7 +469,8 @@ if len(sys.argv) > 0:
                 continue
             TEST.write('    master1.agreement.init(SUFFIX, HOST_MASTER_' +
                        str(idx) + ', PORT_MASTER_' + str(idx) + ')\n')
-            TEST.write('    master1.waitForReplInit(m1_m' + str(idx) + '_agmt)\n')
+            TEST.write('    master1.waitForReplInit(m1_m' + str(idx) +
+                       '_agmt)\n')
 
         # Hubs
         consumers_inited = False
@@ -396,23 +478,27 @@ if len(sys.argv) > 0:
             idx += 1
             TEST.write('    master1.agreement.init(SUFFIX, HOST_HUB_' +
                    str(idx) + ', PORT_HUB_' + str(idx) + ')\n')
-            TEST.write('    master1.waitForReplInit(m1_h' + str(idx) + '_agmt)\n')
+            TEST.write('    master1.waitForReplInit(m1_h' + str(idx) +
+                       '_agmt)\n')
             for idx in range(consumers):
                 if consumers_inited:
                     continue
                 idx += 1
                 TEST.write('    hub1.agreement.init(SUFFIX, HOST_CONSUMER_' +
                            str(idx) + ', PORT_CONSUMER_' + str(idx) + ')\n')
-                TEST.write('    hub1.waitForReplInit(h1_c' + str(idx) + '_agmt)\n')
+                TEST.write('    hub1.waitForReplInit(h1_c' + str(idx) +
+                           '_agmt)\n')
             consumers_inited = True
 
         # Consumers (master -> consumer)
         if hubs == 0:
             for idx in range(consumers):
                 idx += 1
-                TEST.write('    master1.agreement.init(SUFFIX, HOST_CONSUMER_' +
-                           str(idx) + ', PORT_CONSUMER_' + str(idx) + ')\n')
-                TEST.write('    master1.waitForReplInit(m1_c' + str(idx) + '_agmt)\n')
+                TEST.write('    master1.agreement.init(SUFFIX, ' +
+                           'HOST_CONSUMER_' + str(idx) + ', PORT_CONSUMER_' +
+                           str(idx) + ')\n')
+                TEST.write('    master1.waitForReplInit(m1_c' + str(idx) +
+                           '_agmt)\n')
 
         TEST.write('\n')
 
@@ -420,7 +506,7 @@ if len(sys.argv) > 0:
         # Write replicaton check
         #
         if agmt_count > 0:
-            # Find the lowest replica type in the deployment(consumer -> master)
+            # Find the lowest replica type (consumer -> master)
             if consumers > 0:
                 replica = 'consumer1'
             elif hubs > 0:
@@ -428,7 +514,8 @@ if len(sys.argv) > 0:
             else:
                 replica = 'master2'
             TEST.write('    # Check replication is working...\n')
-            TEST.write('    if master1.testReplication(DEFAULT_SUFFIX, ' + replica + '):\n')
+            TEST.write('    if master1.testReplication(DEFAULT_SUFFIX, ' +
+                       replica + '):\n')
             TEST.write("        log.info('Replication is working.')\n")
             TEST.write('    else:\n')
             TEST.write("        log.fatal('Replication is not working.')\n")
@@ -465,15 +552,22 @@ if len(sys.argv) > 0:
                 idx = str(idx)
             TEST.write('    # Creating standalone instance ' + idx + '...\n')
             TEST.write('    standalone' + idx + ' = DirSrv(verbose=False)\n')
-            TEST.write('    args_instance[SER_HOST] = HOST_STANDALONE' + idx + '\n')
-            TEST.write('    args_instance[SER_PORT] = PORT_STANDALONE' + idx + '\n')
-            TEST.write('    args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE' + idx + '\n')
-            TEST.write('    args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX\n')
-            TEST.write('    args_standalone' + idx + ' = args_instance.copy()\n')
-            TEST.write('    standalone' + idx + '.allocate(args_standalone' + idx + ')\n')
+            TEST.write('    args_instance[SER_HOST] = HOST_STANDALONE' +
+                       idx + '\n')
+            TEST.write('    args_instance[SER_PORT] = PORT_STANDALONE' +
+                       idx + '\n')
+            TEST.write('    args_instance[SER_SERVERID_PROP] = ' +
+                       'SERVERID_STANDALONE' + idx + '\n')
+            TEST.write('    args_instance[SER_CREATION_SUFFIX] = ' +
+                       'DEFAULT_SUFFIX\n')
+            TEST.write('    args_standalone' + idx + ' = args_instance.copy' +
+                       '()\n')
+            TEST.write('    standalone' + idx + '.allocate(args_standalone' +
+                       idx + ')\n')
 
             # Get the status of the instance and restart it if it exists
-            TEST.write('    instance_standalone' + idx + ' = standalone' + idx + '.exists()\n')
+            TEST.write('    instance_standalone' + idx + ' = standalone' +
+                       idx + '.exists()\n')
 
             # Remove the instance
             TEST.write('    if instance_standalone' + idx + ':\n')
@@ -503,12 +597,20 @@ if len(sys.argv) > 0:
         TEST.write('def test_ticket' + ticket + '(topology):\n')
         TEST.write("    '''\n")
         if repl_deployment:
-            TEST.write('    Write your replication testcase here.\n\n')
-            TEST.write('    To access each DirSrv instance use:  topology.master1, topology.master2,\n' +
-                       '        ..., topology.hub1, ..., topology.consumer1, ...\n')
+            TEST.write('    """Write your replication testcase here.\n\n')
+            TEST.write('    To access each DirSrv instance use:  ' +
+                       'topology.master1, topology.master2,\n' +
+                       '        ..., topology.hub1, ..., topology.consumer1' +
+                       ',...\n\n')
+            TEST.write('    Also, if you need any testcase initialization,\n')
+            TEST.write('    please, write additional fixture for that' +
+                       '(include ' + 'finalizer).\n')
         else:
-            TEST.write('    Write your testcase here...\n')
-        TEST.write("    '''\n\n")
+            TEST.write('    """Write your testcase here...\n\n')
+            TEST.write('    Also, if you need any testcase initialization,\n')
+            TEST.write('    please, write additional fixture for that' +
+                       '(include finalizer).\n')
+        TEST.write('    """\n\n')
         TEST.write("    log.info('Test complete')\n")
         TEST.write("\n\n")
     else:
@@ -520,43 +622,11 @@ if len(sys.argv) > 0:
 
         # Write the first initial empty test function
         TEST.write('def test_' + suite + '_#####(topology):\n')
-        TEST.write("    '''\n")
-        TEST.write('    Write a single test here...\n')
-        TEST.write("    '''\n\n    return\n\n\n")
-
-    #
-    # Write the final function here - delete each instance
-    #
-    if ticket:
-        TEST.write('def test_ticket' + ticket + '_final(topology):\n')
-    else:
-        # suite
-        TEST.write('def test_' + suite + '_final(topology):\n')
-    if repl_deployment:
-        for idx in range(masters):
-            idx += 1
-            TEST.write('    topology.master' + str(idx) + '.delete()\n')
-        for idx in range(hubs):
-            idx += 1
-            TEST.write('    topology.hub' + str(idx) + '.delete()\n')
-        for idx in range(consumers):
-            idx += 1
-            TEST.write('    topology.consumer' + str(idx) + '.delete()\n')
-    else:
-        for idx in range(instances):
-            idx += 1
-            if idx == 1:
-                idx = ''
-            else:
-                idx = str(idx)
-            TEST.write('    topology.standalone' + idx + '.delete()\n')
-
-    if ticket:
-        TEST.write("    log.info('Testcase PASSED')\n")
-    else:
-        # suite
-        TEST.write("    log.info('" + suite + " test suite PASSED')\n")
-    TEST.write('\n\n')
+        TEST.write('    """Write a single test here...\n\n')
+        TEST.write('    Also, if you need any test suite initialization,\n')
+        TEST.write('    please, write additional fixture for that(include ' +
+                   'finalizer).\n')
+        TEST.write('    """\n\n    return\n\n\n')
 
     #
     # Write the main function
@@ -576,7 +646,10 @@ if len(sys.argv) > 0:
     TEST.write('\n\n')
 
     TEST.write("if __name__ == '__main__':\n")
-    TEST.write('    run_isolated()\n\n')
+    TEST.write('    # Run isolated\n')
+    TEST.write('    # -s for DEBUG mode\n')
+    TEST.write('    CURRENT_FILE = os.path.realpath(__file__)\n')
+    TEST.write('    pytest.main("-s %s" % CURRENT_FILE)\n')
 
     #
     # Done, close things up
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 2adf2f8..00e78a7 100644
--- a/ldap/servers/slapd/back-ldbm/index.c
+++ b/ldap/servers/slapd/back-ldbm/index.c
@@ -727,31 +727,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;
-                        }
                     } 
                 }
 
-- 
2.4.3