From 407e89e338c981c31bf1920c1ed28575a69de6e0 Mon Sep 17 00:00:00 2001 From: Thierry Bordaz Date: Feb 05 2019 15:08:37 +0000 Subject: Ticket 49658 - In replicated topology a single-valued attribute can diverge Bug Description: When deleting a specific value of a single valued attribute, the deleted value can be erronously resurrected. Fix Description: This second fix is a rewrite of entry state resolution. The original function (resolve_attribute_state_single_valued) implemented a main algorythm but it was heavily merged with resolution of specific cases. It was too difficult to make the function understandable and preserving the handling of the specific cases. The risk of that rewrite fix is that I can not guarantee it fully covers the set of specific cases https://pagure.io/389-ds-base/issue/49658 Reviewed by: William Brown (Thanks !!) Platforms tested: F27 Flag Day: no Doc impact: no --- diff --git a/dirsrvtests/tests/tickets/ticket49658_test.py b/dirsrvtests/tests/tickets/ticket49658_test.py new file mode 100644 index 0000000..53522df --- /dev/null +++ b/dirsrvtests/tests/tickets/ticket49658_test.py @@ -0,0 +1,4264 @@ +import logging +import pytest +import os +import ldap +import time +import sys +print(sys.path) +from lib389 import Entry +from lib389._constants import DEFAULT_SUFFIX +from lib389.idm.user import UserAccounts, TEST_USER_PROPERTIES +from lib389.topologies import topology_m3 as topo + +DEBUGGING = os.getenv("DEBUGGING", default=False) +if DEBUGGING: + logging.getLogger(__name__).setLevel(logging.DEBUG) +else: + logging.getLogger(__name__).setLevel(logging.INFO) +log = logging.getLogger(__name__) + + +MAX_EMPLOYEENUMBER_USER = 20 +MAX_STANDARD_USER = 100 +MAX_USER = MAX_STANDARD_USER + MAX_EMPLOYEENUMBER_USER +EMPLOYEENUMBER_RDN_START = 0 + +USER_UID='user_' +BASE_DISTINGUISHED = 'ou=distinguished,ou=people,%s' % (DEFAULT_SUFFIX) +BASE_REGULAR = 'ou=regular,ou=people,%s' % (DEFAULT_SUFFIX) + +def _user_get_dn(no): + uid = '%s%d' % (USER_UID, no) + dn = 'uid=%s,%s' % (uid, BASE_REGULAR) + return (uid, dn) + +def add_user(server, no, init_val): + (uid, dn) = _user_get_dn(no) + log.fatal('Adding user (%s): ' % dn) + server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'], + 'uid': [uid], + 'sn' : [uid], + 'cn' : [uid], + 'employeeNumber': init_val}))) + return dn + +def _employeenumber_user_get_dn(no): + employeeNumber = str(no) + dn = 'employeeNumber=%s,%s' % (employeeNumber, BASE_DISTINGUISHED) + return (employeeNumber, dn) + +def add_employeenumber_user(server, no): + (uid, dn) = _employeenumber_user_get_dn(EMPLOYEENUMBER_RDN_START + no) + log.fatal('Adding user (%s): ' % dn) + server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'], + 'uid': [uid], + 'sn' : [uid], + 'cn' : [uid], + 'employeeNumber': str(EMPLOYEENUMBER_RDN_START + no)}))) + return dn + +def save_stuff(): + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_11 = '11'.encode() + value_1000 = '1000'.encode() + value_13 = '13'.encode() + value_14 = '14'.encode() + + # Step 2 + test_user_dn= add_user(M3, 0, value_11) + log.info('Adding %s on M3' % test_user_dn) + M3.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_11), (ldap.MOD_ADD, 'employeeNumber', value_1000)]) + ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == 1 + + + # Step 3 + # Check the entry is replicated on M1 + for j in range(30): + try: + ent = M1.getEntry(test_user_dn, ldap.SCOPE_BASE,) + if not ent.hasAttr('employeeNumber'): + # wait for the MOD + log.info('M1 waiting for employeeNumber') + time.sleep(1) + continue; + break; + except ldap.NO_SUCH_OBJECT: + time.sleep(1) + pass + time.sleep(1) + ents = M1.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == 1 + + # Check the entry is replicated on M2 + for j in range(30): + try: + ent = M2.getEntry(test_user_dn, ldap.SCOPE_BASE,) + if not ent.hasAttr('employeeNumber'): + # wait for the MOD + log.info('M2 waiting for employeeNumber') + time.sleep(1) + continue; + + break; + except ldap.NO_SUCH_OBJECT: + time.sleep(1) + pass + time.sleep(1) + ents = M2.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == 1 + +def test_ticket49658_init(topo): + """Specify a test case purpose or name here + + :id: 0 + :setup: 3 Master Instances + :steps: + 1. Create 3 suppliers + 2. Create on M3 MAX_USER test entries having a single-value attribute employeeNumber=11 + and update it MOD_DEL 11 + MOD_ADD 1000 + 3. Check they are replicated on M1 and M2 + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_11 = '11'.encode() + value_1000 = '1000'.encode() + + # Step 2 + M3.add_s(Entry((BASE_DISTINGUISHED, {'objectclass': ['top', 'organizationalUnit'], + 'ou': ['distinguished']}))) + for i in range(MAX_EMPLOYEENUMBER_USER): + test_user_dn= add_employeenumber_user(M3, i) + log.info('Adding %s on M3' % test_user_dn) + ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == (i + 1) + + M3.add_s(Entry((BASE_REGULAR, {'objectclass': ['top', 'organizationalUnit'], + 'ou': ['regular']}))) + for i in range(MAX_STANDARD_USER): + test_user_dn= add_user(M3, i, value_11) + log.info('Adding %s on M3' % test_user_dn) + M3.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_11), (ldap.MOD_ADD, 'employeeNumber', value_1000)]) + ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == (MAX_EMPLOYEENUMBER_USER + i + 1) + + + # Step 3 + # Check the last entry is replicated on M1 + (uid, test_user_dn) = _user_get_dn(MAX_STANDARD_USER - 1) + for j in range(30): + try: + ent = M1.getEntry(test_user_dn, ldap.SCOPE_BASE,) + if not ent.hasAttr('employeeNumber'): + # wait for the MOD + log.info('M1 waiting for employeeNumber') + time.sleep(1) + continue; + break; + except ldap.NO_SUCH_OBJECT: + time.sleep(1) + pass + time.sleep(1) + ents = M1.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_USER + + # Check the last entry is replicated on M2 + for j in range(30): + try: + ent = M2.getEntry(test_user_dn, ldap.SCOPE_BASE,) + if not ent.hasAttr('employeeNumber'): + # wait for the MOD + log.info('M2 waiting for employeeNumber') + time.sleep(1) + continue; + + break; + except ldap.NO_SUCH_OBJECT: + time.sleep(1) + pass + time.sleep(1) + ents = M2.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_USER + +def test_ticket49658_0(topo): + """Do MOD(DEL+ADD) and replicate MOST RECENT first + M1: MOD(DEL+ADD) -> V1 + M2: MOD(DEL+ADD) -> V1 + expected: V1 + + :id: 0 + :setup: 3 Master Instances + 1. using user_0 where employNumber=1000 + :steps: + 1. Create 3 suppliers + 2. Isolate M1 and M2 by pausing the replication agreements + 3. On M1 do MOD_DEL 1000 + MOD_ADD_13 + 4. On M2 do MOD_DEL 1000 + MOD_ADD_13 + 5. Enable replication agreement M2 -> M3, so that update step 6 is replicated first + 6. Enable replication agreement M1 -> M3, so that update step 5 is replicated second + 7. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000'.encode() + last = '0' + value_end = last.encode() + theFilter = '(employeeNumber=%s)' % last + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 2 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 3 + # Oldest update + # check that the entry on M1 contains employeeNumber= + M1.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)]) + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + assert len(ents) == 1 + time.sleep(1) + + # Step 4 + # More recent update + # check that the entry on M2 contains employeeNumber= + M2.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)]) + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + +def test_ticket49658_1(topo): + """Do MOD(DEL+ADD) and replicate OLDEST first + M2: MOD(DEL+ADD) -> V1 + M1: MOD(DEL+ADD) -> V1 + expected: V1 + + :id: 1 + :setup: 3 Master Instances + 1. using user_1 where employNumber=1000 + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M2 do MOD_DEL 1000 + MOD_ADD_13 + 3. On M1 do MOD_DEL 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000'.encode() + last = '1' + value_end = last.encode() + theFilter = '(employeeNumber=%s)' % last + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(1)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M2 contains employeeNumber= + M2.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)]) + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + M1.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)]) + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + +def test_ticket49658_2(topo): + """Do MOD(ADD+DEL) and replicate OLDEST first + M2: MOD(ADD+DEL) -> V1 + M1: MOD(ADD+DEL) -> V1 + expected: V1 + + :id: 2 + :setup: 3 Master Instances + 1. using user_2 where employNumber=1000 + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M2 do MOD_DEL 1000 + MOD_ADD_13 + 3. On M1 do MOD_DEL 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000'.encode() + last = '2' + value_end = last.encode() + theFilter = '(employeeNumber=%s)' % last + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M2 contains employeeNumber= + M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)]) + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end), (ldap.MOD_DELETE, 'employeeNumber', value_1000)]) + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + +def test_ticket49658_3(topo): + """Do MOD(ADD+DEL) and replicate MOST RECENT first + M1: MOD(ADD+DEL) -> V1 + M2: MOD(ADD+DEL) -> V1 + expected: V1 + :id: 3 + :setup: 3 Master Instances + 1. using user_2 where employNumber=1000 + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do MOD_DEL 1000 + MOD_ADD_13 + 3. On M2 do MOD_DEL 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000'.encode() + last = '3' + value_end = last.encode() + theFilter = '(employeeNumber=%s)' % last + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)]) + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end), (ldap.MOD_DELETE, 'employeeNumber', value_1000)]) + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + +def test_ticket49658_4(topo): + """Do MOD(ADD+DEL) MOD(REPL) and replicate MOST RECENT first + M1: MOD(ADD+DEL) -> V1 + M2: MOD(REPL) -> V1 + expected: V1 + + :id: 4 + :setup: 3 Master Instances + 1. using user_2 where employNumber=1000 + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do MOD_DEL 1000 + MOD_ADD_13 + 3. On M2 do MOD_REPL _13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000'.encode() + last = '4' + value_end = last.encode() + theFilter = '(employeeNumber=%s)' % last + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)]) + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + M2.modify_s(test_user_dn, [(ldap.MOD_REPLACE, 'employeeNumber', value_end)]) + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + +def test_ticket49658_5(topo): + """Do MOD(REPL) MOD(ADD+DEL) and replicate MOST RECENT first + M1: MOD(REPL) -> V1 + M2: MOD(ADD+DEL) -> V1 + expected: V1 + :id: 5 + :setup: 3 Master Instances + 1. using user_2 where employNumber=1000 + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do MOD_DEL 1000 + MOD_ADD_13 + 3. On M2 do MOD_REPL _13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000'.encode() + last = '5' + value_end = last.encode() + theFilter = '(employeeNumber=%s)' % last + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + M1.modify_s(test_user_dn, [(ldap.MOD_REPLACE, 'employeeNumber', value_end)]) + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)]) + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end)) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end + +def test_ticket49658_6(topo): + """Do + M1: MOD(REPL) -> V1 + M2: MOD(ADD+DEL) -> V2 + expected: V2 + + :id: 6 + :setup: 3 Master Instances + 1. using user_2 where employNumber=1000 + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do MOD_DEL 1000 + MOD_ADD_13 + 3. On M2 do MOD_REPL _13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000' + last = '6' + value_S1 = '6.1' + value_S2 = '6.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())], + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].modify_s(test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].modify_s(test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_7(topo): + """Do + M1: MOD(ADD+DEL) -> V1 + M2: MOD(REPL) -> V2 + expected: V2 + + :id: 7 + :setup: 3 Master Instances + :steps: + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000' + last = '7' + value_S1 = '7.1' + value_S2 = '7.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S1.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())], + "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())], + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].modify_s(test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].modify_s(test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_8(topo): + """Do + M1: MOD(DEL+ADD) -> V1 + M2: MOD(REPL) -> V2 + expected: V2 + + :id: 8 + :setup: 3 Master Instances + :steps: + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000' + last = '8' + value_S1 = '8.1' + value_S2 = '8.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())], + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].modify_s(test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].modify_s(test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + +def test_ticket49658_9(topo): + """Do + M1: MOD(REPL) -> V1 + M2: MOD(DEL+ADD) -> V2 + expected: V2 + + :id: 9 + :setup: 3 Master Instances + :steps: + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000' + last = '9' + value_S1 = '9.1' + value_S2 = '9.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())], + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].modify_s(test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].modify_s(test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + + +def test_ticket49658_10(topo): + """Do + M1: MOD(REPL) -> V1 + M2: MOD(REPL) -> V2 + expected: V2 + + :id: 10 + :setup: 3 Master Instances + :steps: + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000' + last = '10' + value_S1 = '10.1' + value_S2 = '10.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())], + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].modify_s(test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].modify_s(test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + + +def test_ticket49658_11(topo): + """Do + M2: MOD(REPL) -> V2 + M1: MOD(REPL) -> V1 + expected: V1 + + :id: 11 + :setup: 3 Master Instances + :steps: + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000' + last = '11' + value_S1 = '11.1' + value_S2 = '11.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())], + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S2"].modify_s(test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S1"].modify_s(test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_12(topo): + """Do + M2: MOD(ADD+DEL) -> V2 + M1: MOD(REPL) -> V1 + expected: V1 + + :id: 12 + :setup: 3 Master Instances + 1. using user_2 where employNumber=1000 + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do MOD_DEL 1000 + MOD_ADD_13 + 3. On M2 do MOD_REPL _13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000' + last = '12' + value_S1 = '12.1' + value_S2 = '12.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())], + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S2"].modify_s(test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S1"].modify_s(test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_13(topo): + """Do + M2: MOD(DEL+ADD) -> V2 + M1: MOD(REPL) -> V1 + expected: V1 + + :id: 13 + :setup: 3 Master Instances + 1. using user_2 where employNumber=1000 + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do MOD_DEL 1000 + MOD_ADD_13 + 3. On M2 do MOD_REPL _13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000' + last = '13' + value_S1 = '13.1' + value_S2 = '13.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())], + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S2"].modify_s(test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S1"].modify_s(test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + +def test_ticket49658_14(topo): + """Do + M2: MOD(DEL+ADD) -> V2 + M1: MOD(DEL+ADD) -> V1 + expected: V1 + + :id: 14 + :setup: 3 Master Instances + 1. using user_2 where employNumber=1000 + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do MOD_DEL 1000 + MOD_ADD_13 + 3. On M2 do MOD_REPL _13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000' + last = '14' + value_S1 = '14.1' + value_S2 = '14.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())], + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S2"].modify_s(test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S1"].modify_s(test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_15(topo): + """Do + M2: MOD(ADD+DEL) -> V2 + M1: MOD(DEL+ADD) -> V1 + expected: V1 + + :id: 15 + :setup: 3 Master Instances + 1. using user_2 where employNumber=1000 + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do MOD_DEL 1000 + MOD_ADD_13 + 3. On M2 do MOD_REPL _13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_1000 = '1000' + last = '15' + value_S1 = '15.1' + value_S2 = '15.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())], + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S2"].modify_s(test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S1"].modify_s(test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + + #time.sleep(60) + # Step 7 + # Renable M2 before M1 so that on M3, the most recent update is replicated before + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + # Step 8 + # Renable M1 so that on M3 oldest update is now replicated + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_STANDARD_USER + ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + +def _resume_ra_M1_then_M2(M1, M2, M3): + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + + time.sleep(4) + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + time.sleep(4) + +def _resume_ra_M2_then_M1(M1, M2, M3): + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + for ra in agreement_m2_m1, agreement_m2_m3: + M2.agreement.resume(ra[0].dn) + + time.sleep(4) + for ra in agreement_m1_m2, agreement_m1_m3: + M1.agreement.resume(ra[0].dn) + time.sleep(4) + + +def test_ticket49658_16(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V1 + expected: V1 + resume order: M2, M1 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '1' + last = '1' + value_S1 = '1.1' + value_S2 = value_S1 + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S2_MODRDN": value_S2, + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + + _resume_ra_M2_then_M1(M1, M2, M3) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + +def test_ticket49658_17(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + expected: V2 + resume order: M2 then M1 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '2' + last = '2' + value_S1 = '2.1' + value_S2 = '2.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S2_MODRDN": value_S2, + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + + _resume_ra_M2_then_M1(M1, M2, M3) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_18(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + expected: V2 + resume order: M1 then M2 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '2' + last = '3' + value_S1 = '3.1' + value_S2 = '3.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S2_MODRDN": value_S2, + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + + _resume_ra_M1_then_M2(M1, M2, M3) + + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_19(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(REPL) -> V1 + Replicate order: M2 then M1 + expected: V1 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '3' + last = '4' + value_S1 = '4.1' + value_S2 = '4.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MODRDN": value_S2, + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + + _resume_ra_M2_then_M1(M1, M2, M3) + + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_20(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(REPL) -> V1 + Replicate order: M1 then M2 + expected: V1 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '3' + last = '5' + value_S1 = '5.1' + value_S2 = '5.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MODRDN": value_S2, + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + + _resume_ra_M1_then_M2(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_21(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(DEL/ADD) -> V1 + Replicate order: M2 then M1 + expected: V1 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '3' + last = '6' + value_S1 = '6.1' + value_S2 = '6.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())], + "S2_MODRDN": value_S2, + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + + _resume_ra_M2_then_M1(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_22(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(DEL/ADD) -> V1 + Replicate: M1 then M2 + expected: V1 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '3' + last = '7' + value_S1 = '7.1' + value_S2 = '7.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())], + "S2_MODRDN": value_S2, + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + + _resume_ra_M1_then_M2(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_23(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(REPL) -> V1 + M2: MOD(REPL) -> V2 + Replicate order: M2 then M1 + expected: V2 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '7' + last = '8' + value_S1 = '8.1' + value_S2 = '8.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())], + "S2_MODRDN": value_S2, + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"]) + description["S2"].modify_s(new_test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + _resume_ra_M2_then_M1(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_24(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(REPL) -> V1 + M2: MOD(REPL) -> V2 + Replicate order: M1 then M2 + expected: V2 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '7' + last = '9' + value_S1 = '9.1' + value_S2 = '9.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())], + "S2_MODRDN": value_S2, + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"]) + description["S2"].modify_s(new_test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + _resume_ra_M1_then_M2(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_25(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(REPL) -> V1 + M2: MOD(DEL/ADD) -> V2 + Replicate order: M1 then M2 + expected: V2 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '7' + last = '10' + value_S1 = '10.1' + value_S2 = '10.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())], + "S2_MODRDN": value_S2, + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"]) + description["S2"].modify_s(new_test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + _resume_ra_M1_then_M2(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_26(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(REPL) -> V1 + M2: MOD(DEL/ADD) -> V2 + Replicate order: M2 then M1 + expected: V2 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '7' + last = '11' + value_S1 = '11.1' + value_S2 = '11.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())], + "S2_MODRDN": value_S2, + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"]) + description["S2"].modify_s(new_test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + _resume_ra_M2_then_M1(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_27(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(DEL/ADD) -> V1 + M2: MOD(REPL) -> V2 + Replicate order: M1 then M2 + expected: V2 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '7' + last = '12' + value_S1 = '12.1' + value_S2 = '12.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())], + "S2_MODRDN": value_S2, + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"]) + description["S2"].modify_s(new_test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + _resume_ra_M1_then_M2(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_28(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(DEL/ADD) -> V1 + M2: MOD(REPL) -> V2 + Replicate order: M2 then M1 + expected: V2 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '7' + last = '13' + value_S1 = '13.1' + value_S2 = '13.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())], + "S2_MODRDN": value_S2, + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"]) + description["S2"].modify_s(new_test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + _resume_ra_M2_then_M1(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + +def test_ticket49658_29(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(DEL/ADD) -> V1 + M2: MOD(DEL/ADD) -> V2 + Replicate order: M1 then M2 + expected: V2 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '7' + last = '14' + value_S1 = '14.1' + value_S2 = '14.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())], + "S2_MODRDN": value_S2, + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"]) + description["S2"].modify_s(new_test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + _resume_ra_M1_then_M2(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_30(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(DEL/ADD) -> V1 + M2: MOD(DEL/ADD) -> V2 + Replicate order: M2 then M1 + expected: V2 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '7' + last = '15' + value_S1 = '15.1' + value_S2 = '15.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())], + "S2_MODRDN": value_S2, + "expected": value_S2} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"]) + description["S2"].modify_s(new_test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + _resume_ra_M2_then_M1(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_31(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(REPL) -> V1 + M2: MOD(REPL) -> V2 + M2: MODRDN -> V1 + Replicate order: M2 then M1 + expected: V1 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '7' + last = '16' + value_S1 = '16.1' + value_S2 = '16.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())], + "S2_MODRDN_1": value_S2, + "S2_MODRDN_2": value_S1, + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"]) + description["S2"].modify_s(new_test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"]) + assert len(ents) == 1 + time.sleep(1) + + _resume_ra_M2_then_M1(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + +def test_ticket49658_32(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(REPL) -> V1 + M2: MOD(REPL) -> V2 + M2: MODRDN -> V1 + Replicate order: M1 then M2 + expected: V1 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '7' + last = '17' + value_S1 = '17.1' + value_S2 = '17.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())], + "S2_MODRDN_1": value_S2, + "S2_MODRDN_2": value_S1, + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"]) + description["S2"].modify_s(new_test_user_dn, description["S2_MOD"]) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2) + assert len(ents) == 1 + + description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"]) + assert len(ents) == 1 + time.sleep(1) + + _resume_ra_M1_then_M2(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_33(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(REPL) -> V1 + M2: MODRDN -> V1 + Replicate order: M2 then M1 + expected: V1 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '7' + last = '18' + value_S1 = '18.1' + value_S2 = '18.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MODRDN_1": value_S2, + "S2_MODRDN_2": value_S1, + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"]) + description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"]) + assert len(ents) == 1 + time.sleep(1) + + _resume_ra_M2_then_M1(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + +def test_ticket49658_34(topo): + """Do + M1: MODRDN -> V1 + M2: MODRDN -> V2 + M1: MOD(REPL) -> V1 + M2: MODRDN -> V1 + Replicate order: M1 then M2 + expected: V1 + + :id: 16 + :setup: 3 Master Instances + 1. Use employeenumber=1000,ou=distinguished,ou=people, + :steps: + 1. Isolate M1 and M2 by pausing the replication agreements + 2. On M1 do DEL+ADD 1000 + MOD_ADD_13 + 3. On M2 do DEL+ADD 1000 + MOD_ADD_13 + 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first + 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second + 6. Check that the employeeNumber is 13 on all servers + :expectedresults: + 1. Fill in the result that is expected + 2. For each test step + """ + + # If you need any test suite initialization, + # please, write additional fixture for that (including finalizer). + # Topology for suites are predefined in lib389/topologies.py. + + # If you need host, port or any other data about instance, + # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) + + + + if DEBUGGING: + # Add debugging steps(if any)... + pass + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + value_init = '7' + last = '19' + value_S1 = '19.1' + value_S2 = '19.2' + + description = { + "S1": M1, + "S2": M2, + "S1_MODRDN": value_S1, + "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())], + "S2_MODRDN_1": value_S2, + "S2_MODRDN_2": value_S1, + "expected": value_S1} + + # This test takes the user_1 + (uid, test_user_dn) = _employeenumber_user_get_dn(int(last)) + + # + # Step 4 + # + # disable all RA from M1 and M2 + # only M3 can replicate the update + # + agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port) + agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port) + agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + M1.agreement.pause(agreement_m1_m2[0].dn) + M1.agreement.pause(agreement_m1_m3[0].dn) + M2.agreement.pause(agreement_m2_m1[0].dn) + M2.agreement.pause(agreement_m2_m3[0].dn) + + # Step 5 + # Oldest update + # check that the entry on M1 contains employeeNumber= + description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"]) + assert len(ents) == 1 + time.sleep(1) + + # Step 6 + # More recent update + # check that the entry on M2 contains employeeNumber= + description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"]) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"]) + description["S1"].modify_s(new_test_user_dn, description["S1_MOD"]) + ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1) + assert len(ents) == 1 + time.sleep(1) + + (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"]) + description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1) + ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"]) + assert len(ents) == 1 + time.sleep(1) + + _resume_ra_M1_then_M2(M1, M2, M3) + + #time.sleep(3600) + # Step 9 + # Check that M1 still contains employeeNumber= + ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M2 still contains employeeNumber= + ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() + + # Check that M3 still contain employeeNumber and it contains employeeNumber= + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)') + assert len(ents) == MAX_EMPLOYEENUMBER_USER + ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"]) + log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"])) + assert len(ents) == 1 + assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode() +if __name__ == '__main__': + # Run isolated + # -s for DEBUG mode + CURRENT_FILE = os.path.realpath(__file__) + pytest.main(["-s", CURRENT_FILE]) + diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c index 58f7870..080eb15 100644 --- a/ldap/servers/slapd/entrywsi.c +++ b/ldap/servers/slapd/entrywsi.c @@ -359,6 +359,13 @@ entry_add_present_attribute_wsi(Slapi_Entry *e, Slapi_Attr *a) * Preserves LDAP Information Model constraints, * returning an LDAP result code. */ +static void entry_dump_stateinfo(char *msg, Slapi_Entry* e); +static Slapi_Value *attr_most_recent_deleted_value(Slapi_Attr *a); +static void resolve_single_valued_two_values(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, Slapi_Value *current_value, Slapi_Value *second_current_value); +static void resolve_single_valued_check_restore_deleted_value(Slapi_Entry *e, Slapi_Attr *a); +static void resolve_single_valued_zap_current(Slapi_Entry *e, Slapi_Attr *a); +static void resolve_single_valued_set_adcsn(Slapi_Attr *a); +static void resolve_single_valued_zap_deleted(Slapi_Attr *a); static void resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state); static void resolve_attribute_state_deleted_to_present(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate); static void resolve_attribute_state_present_to_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate); @@ -387,6 +394,20 @@ entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **b return retVal; } +/* Used for debug purpose, it dumps into the error log the + * entry with the replication stateinfo + */ +static void +entry_dump_stateinfo(char *msg, Slapi_Entry* e) +{ + char *s; + int32_t len = 0; + + s = slapi_entry2str_with_options(e, &len, SLAPI_DUMP_STATEINFO); + slapi_log_err(SLAPI_LOG_ERR, msg, "%s\n", s); + slapi_ch_free((void **)&s); +} + static int entry_add_present_values_wsi_single_valued(Slapi_Entry *e, const char *type, struct berval **bervals, const CSN *csn, int urp, long flags) { @@ -705,6 +726,10 @@ entry_delete_present_values_wsi_single_valued(Slapi_Entry *e, const char *type, /* The attribute is single valued and the value was successful deleted */ /* but there could have been an add in the same operation, so double check */ if (valueset_isempty(&a->a_present_values)) { + /* A doubt here, a direct update deletes the last value + * of a single valued attribute. It will only contain deleted values. + * Why not setting the adcsn (attr_set_deletion_csn) ? + */ entry_present_attribute_to_deleted_attribute(e, a); } } else if (retVal != LDAP_SUCCESS) { @@ -1229,169 +1254,254 @@ resolve_attribute_state_present_to_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_ } } -static void -resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state) +/* Retrieve from the deleted values the one that + * was the most recently deleted. Based on its vdcsn + */ +static Slapi_Value * +attr_most_recent_deleted_value(Slapi_Attr *a) { - Slapi_Value *current_value = NULL; - Slapi_Value *pending_value = NULL; - Slapi_Value *new_value = NULL; - const CSN *current_value_vucsn; - const CSN *pending_value_vucsn; - const CSN *pending_value_vdcsn; - const CSN *adcsn; + Slapi_Value *v, *most_recent_v; int i; + CSN *vdcsn, *most_recent_vdcsn; - /* - * this call makes sure that the attribute does not have a pending_value - * or deletion_csn which is before the current_value. - */ - i = slapi_attr_first_value(a, ¤t_value); - if (i != -1) { - slapi_attr_next_value(a, i, &new_value); - } - attr_first_deleted_value(a, &pending_value); - /* purge_attribute_state_single_valued */ - adcsn = attr_get_deletion_csn(a); - current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED); - pending_value_vucsn = value_get_csn(pending_value, CSN_TYPE_VALUE_UPDATED); - pending_value_vdcsn = value_get_csn(pending_value, CSN_TYPE_VALUE_DELETED); - if ((pending_value != NULL && (csn_compare(adcsn, pending_value_vucsn) < 0)) || - (pending_value == NULL && (csn_compare(adcsn, current_value_vucsn) < 0))) { - attr_set_deletion_csn(a, NULL); - adcsn = NULL; + vdcsn = NULL; + most_recent_vdcsn = NULL; + i = attr_first_deleted_value(a, &v); + most_recent_v = v; + + while (i != -1) { + vdcsn = value_get_csn(v, CSN_TYPE_VALUE_DELETED); + + if (csn_compare((const CSN *)most_recent_vdcsn, (const CSN *)vdcsn) < 0) { + most_recent_v = v; + most_recent_vdcsn = vdcsn; + } + i = attr_next_deleted_value(a, i, &v); } + return most_recent_v; +} - /* in the case of the following: - * add: value2 - * delete: value1 - * we will have current_value with VUCSN CSN1 - * and pending_value with VDCSN CSN2 - * and new_value == NULL - * current_value != pending_value - * and - * VUCSN == VDCSN (ignoring subseq) - * even though value1.VDCSN > value2.VUCSN - * value2 should still win because the value is _different_ - */ - if (current_value && pending_value && !new_value && !adcsn && - (0 != slapi_value_compare(a, current_value, pending_value)) && - (0 == csn_compare_ext(current_value_vucsn, pending_value_vdcsn, CSN_COMPARE_SKIP_SUBSEQ))) { - /* just remove the deleted value */ - entry_deleted_value_to_zapped_value(a, pending_value); - pending_value = NULL; - } else if (current_value && pending_value && !new_value && adcsn && - (attribute_state == ATTRIBUTE_DELETED) && - current_value_vucsn && !pending_value_vucsn && pending_value_vdcsn && - (csn_compare(current_value_vucsn, pending_value_vdcsn) > 0) && - (csn_compare(adcsn, pending_value_vdcsn) == 0)) { - /* in the case of the following: - * beginning attr state is a deleted value - * incoming operation is - * add: newvalue - * attribute_state is ATTRIBUTE_DELETED - * so we have both a current_value and a pending_value - * new_value is NULL - * current_value_vucsn is CSN1 - * pending_value_vucsn is NULL - * pending_value_vdcsn is CSN2 - * adcsn is CSN2 == pending_value_vdcsn - * CSN1 > CSN2 - * since the pending_value is deleted, and the current_value has - * a greater CSN, we should keep the current_value and zap - * the pending_value +/* This routine applies for single valued attribute. + * The attribute has two current values, it keeps the most recent one + * and zap the oldest + */ +static void +resolve_single_valued_two_values(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, Slapi_Value *current_value, Slapi_Value *second_current_value) +{ + + CSN *current_value_vucsn; + CSN *second_current_value_vucsn; + Slapi_Value *value_to_zap; + + current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED); + second_current_value_vucsn = value_get_csn(second_current_value, CSN_TYPE_VALUE_UPDATED); + + /* First determine which present value will be zapped */ + if (csn_compare((const CSN *)second_current_value_vucsn, (const CSN *)current_value_vucsn) < 0) { + /* + * The second value is older but was distinguished at the time the current value was added + * then the second value should become current */ - /* just remove the deleted value */ - entry_deleted_value_to_zapped_value(a, pending_value); - /* move the attribute to the present attributes list */ - entry_deleted_attribute_to_present_attribute(e, a); - pending_value = NULL; - attr_set_deletion_csn(a, NULL); - return; /* we are done - we are keeping the present value */ - } else if (new_value == NULL) { - /* check if the pending value should become the current value */ - if (pending_value != NULL) { - if (!value_distinguished_at_csn(e, a, current_value, pending_value_vucsn)) { - /* attribute.current_value = attribute.pending_value; */ - /* attribute.pending_value = NULL; */ - entry_present_value_to_zapped_value(a, current_value); - entry_deleted_value_to_present_value(a, pending_value); - current_value = pending_value; - pending_value = NULL; - current_value_vucsn = pending_value_vucsn; - pending_value_vucsn = NULL; - } + if (value_distinguished_at_csn(e, a, second_current_value, (const CSN *)current_value_vucsn)) { + value_to_zap = current_value; + } else { + /* The second value being not distinguished, zap it as it is a single valued attribute */ + value_to_zap = second_current_value; } - /* check if the current value should be deleted */ - if (current_value != NULL) { - if (csn_compare(adcsn, current_value_vucsn) > 0) /* check if the attribute was deleted after the value was last updated */ - { - if (!value_distinguished_at_csn(e, a, current_value, current_value_vucsn)) { - entry_present_value_to_zapped_value(a, current_value); - current_value = NULL; - current_value_vucsn = NULL; - } - } + + } else { + /* Here the current_value is older than the second_current_value */ + if (value_distinguished_at_csn(e, a, current_value, (const CSN *)second_current_value_vucsn)) { + /* current_value was distinguished at the time the second value was added + * then the current_value should become the current */ + value_to_zap = second_current_value; + } else { + value_to_zap = current_value; } - } else /* addition of a new value */ - { - const CSN *new_value_vucsn = value_get_csn(new_value, CSN_TYPE_VALUE_UPDATED); - if (csn_compare(new_value_vucsn, current_value_vucsn) < 0) { - /* - * if the new value was distinguished at the time the current value was added - * then the new value should become current + } + entry_present_value_to_zapped_value(a, value_to_zap); + + + +} + +/* This routine applies for single valued attribute. + * It checks if the deleted value is more recent than + * the present one. If it is, it resurect the deleted value + * + * This function leaves untouch the adcsn + */ +static void +resolve_single_valued_check_restore_deleted_value(Slapi_Entry *e, Slapi_Attr *a) +{ + Slapi_Value *deleted_value = NULL; + Slapi_Value *current_value = NULL; + + /* Retrieve the deleted and current value */ + deleted_value = attr_most_recent_deleted_value(a); + if (deleted_value == NULL) { + return; + } + slapi_attr_first_value(a, ¤t_value); + + if (current_value == NULL) { + /* An attribute needs a present value */ + entry_deleted_value_to_present_value(a, deleted_value); + } else { + CSN *current_value_vucsn; + CSN *deleted_value_vucsn; + CSN *deleted_value_vdcsn; + + deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED); + deleted_value_vdcsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_DELETED); + current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED); + if (deleted_value_vucsn && + !value_distinguished_at_csn(e, a, current_value, (const CSN *)deleted_value_vucsn) && + (csn_compare((const CSN *)current_value_vucsn, (const CSN *)deleted_value_vucsn) < 0) && + (csn_compare((const CSN *)deleted_value_vdcsn, (const CSN *)current_value_vucsn) < 0)) { + /* the condition to resurrect the deleted value is + * - it is more recent than the current value + * - its value was deleted before the current value + * - the current value is not distinguished */ - if (value_distinguished_at_csn(e, a, new_value, current_value_vucsn)) { - /* attribute.pending_value = attribute.current_value */ - /* attribute.current_value = new_value */ - if (pending_value == NULL) { - entry_present_value_to_deleted_value(a, current_value); - } else { - entry_present_value_to_zapped_value(a, current_value); - } - pending_value = current_value; - current_value = new_value; - new_value = NULL; - pending_value_vucsn = current_value_vucsn; - current_value_vucsn = new_value_vucsn; - } else { - /* new_value= NULL */ - entry_present_value_to_zapped_value(a, new_value); - new_value = NULL; - } - } else /* new value is after the current value */ - { - if (!value_distinguished_at_csn(e, a, current_value, new_value_vucsn)) { - /* attribute.current_value = new_value */ - entry_present_value_to_zapped_value(a, current_value); - current_value = new_value; - new_value = NULL; - current_value_vucsn = new_value_vucsn; - } else /* value is distinguished - check if we should replace the current pending value */ - { - if (csn_compare(new_value_vucsn, pending_value_vucsn) > 0) { - /* attribute.pending_value = new_value */ - entry_deleted_value_to_zapped_value(a, pending_value); - entry_present_value_to_deleted_value(a, new_value); - pending_value = new_value; - new_value = NULL; - pending_value_vucsn = new_value_vucsn; - } - } + entry_present_value_to_zapped_value(a, current_value); + entry_deleted_value_to_present_value(a, deleted_value); } } +} +/* This function deals with single valued attribute + * It zap the current value if the adcsn is more recent and the value is not distinguished + */ +static void +resolve_single_valued_zap_current(Slapi_Entry *e, Slapi_Attr *a) +{ + Slapi_Value *current_value = NULL; + CSN *current_value_vucsn; + CSN *adcsn; - /* - * This call ensures that the attribute does not have a pending_value - * or a deletion_csn that is earlier than the current_value. + /* check if the current value should be deleted because + * older than adcsn and not distinguished */ - /* purge_attribute_state_single_valued */ - if ((pending_value != NULL && (csn_compare(adcsn, pending_value_vucsn) < 0)) || - (pending_value == NULL && (csn_compare(adcsn, current_value_vucsn) < 0))) { + slapi_attr_first_value(a, ¤t_value); + current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED); + adcsn = attr_get_deletion_csn(a); + if (current_value != NULL) { + if (csn_compare((const CSN *)adcsn, (const CSN *) current_value_vucsn) > 0) { + /* the attribute was deleted after the value was last updated */ + if (!value_distinguished_at_csn(e, a, current_value, (const CSN *) current_value_vucsn)) { + entry_present_value_to_zapped_value(a, current_value); + } + } + } +} +/* This function deals with single valued attribute + * It reset the adcsn if + * - there is no deleted value and current value is more recent than the adcsn + * - there is a deleted value and it is more recent than the adcsn + */ +static void +resolve_single_valued_set_adcsn(Slapi_Attr *a) +{ + Slapi_Value *deleted_value = NULL; + Slapi_Value *current_value = NULL; + CSN *current_value_vucsn; + CSN *deleted_value_vucsn; + CSN *adcsn; + + slapi_attr_first_value(a, ¤t_value); + current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED); + deleted_value = attr_most_recent_deleted_value(a); + deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED); + adcsn = attr_get_deletion_csn(a); + if ((deleted_value != NULL && (csn_compare(adcsn, (const CSN *) deleted_value_vucsn) < 0)) || + (deleted_value == NULL && (csn_compare(adcsn, (const CSN *) current_value_vucsn) < 0))) { attr_set_deletion_csn(a, NULL); - adcsn = NULL; } +} +/* This function deals with single valued attribute + * It checks if the deleted value worth to be kept + * + * deleted value is zapped if + * - it is the result of MOD_REPL that is older than current value + * - It is the result of MOD_DEL_ that is belong to the same operation that set the current value + */ +static void +resolve_single_valued_zap_deleted(Slapi_Attr *a) +{ + Slapi_Value *deleted_value = NULL; + Slapi_Value *current_value = NULL; + CSN *current_value_vucsn; + CSN *deleted_value_vucsn; + CSN *deleted_value_vdcsn; + CSN *deleted_value_csn; + PRBool deleted_on_mod_del = PR_FALSE; /* flag if a value was deleted specifically */ + + /* Now determine if the deleted value worth to be kept */ + slapi_attr_first_value(a, ¤t_value); + current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED); + + deleted_value = attr_most_recent_deleted_value(a); + deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED); + deleted_value_vdcsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_DELETED); + + /* get the appropriate csn to take into consideration: either from MOD_REPL or from MOD_DEL_specific */ + if (csn_compare((const CSN *) deleted_value_vdcsn, (const CSN *) deleted_value_vucsn) <= 0) { + deleted_value_csn = deleted_value_vucsn; + } else { + deleted_value_csn = deleted_value_vdcsn; + if (0 == csn_compare_ext((const CSN *) current_value_vucsn, (const CSN *) deleted_value_vdcsn, CSN_COMPARE_SKIP_SUBSEQ)) { + /* the deleted value was specifically delete in the same operation that set the current value */ + deleted_on_mod_del = PR_TRUE; + } + } + if ((csn_compare((const CSN *) deleted_value_csn, (const CSN *) current_value_vucsn) < 0) || deleted_on_mod_del) { + entry_deleted_value_to_zapped_value(a, deleted_value); + } +} + +/* This function deals with single valued attribute + * It does a set of cleanup in the current/deleted values in order + * to conform the schema, take care of distinguished values and only preserve the + * values that worth to be kept. + */ +static void +resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state) +{ + int32_t nbval, i; + Slapi_Value *current_value = NULL; + + /* retrieve the current value(s) */ + slapi_attr_get_numvalues(a, &nbval); + i = slapi_attr_first_value(a, ¤t_value); + + /* If there are several values, first determine which value will be the current (present) one */ + if (nbval > 1) { + /* There are several values for a single valued attribute, keep the most recent one */ + if (i == -1) { + slapi_log_err(SLAPI_LOG_ERR, "resolve_attribute_state_single_valued", "Unexpected state of %s that contains more than one value but can not read the second\n", a->a_type); + } else { + Slapi_Value *second_current_value = NULL; + + slapi_attr_next_value(a, i, &second_current_value); + resolve_single_valued_two_values(e, a, attribute_state, current_value, second_current_value); + } + } + /* There is only one current value (present value) */ + + /* Now determine if the deleted value needs to replace the current value */ + resolve_single_valued_check_restore_deleted_value(e, a); + + /* Now determine if the deleted value worth to be kept (vs. current value) */ + resolve_single_valued_zap_deleted(a); + + /* Now determine if the current value worth to be kept (vs. adcsn) */ + resolve_single_valued_zap_current(e, a); + + /* Now set the adcsn */ + resolve_single_valued_set_adcsn(a); - /* set attribute state */ + /* set the attribute in the correct list in the entry: present or deleted */ + slapi_attr_first_value(a, ¤t_value); if (current_value == NULL) { if (attribute_state == ATTRIBUTE_PRESENT) { entry_present_attribute_to_deleted_attribute(e, a);