From 3827bc9bd26469f5080ad04cf0d223fd3c4f213a Mon Sep 17 00:00:00 2001 From: Thierry Bordaz Date: Wed, 10 Jan 2018 15:42:37 +0100 Subject: [PATCH] Ticket 49463: testcase --- dirsrvtests/tests/tickets/ticket49463_test.py | 286 ++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 dirsrvtests/tests/tickets/ticket49463_test.py diff --git a/dirsrvtests/tests/tickets/ticket49463_test.py b/dirsrvtests/tests/tickets/ticket49463_test.py new file mode 100644 index 000000000..d6242dfac --- /dev/null +++ b/dirsrvtests/tests/tickets/ticket49463_test.py @@ -0,0 +1,286 @@ +import time +import ldap +import logging +import pytest +import os +import re +from lib389._constants import * +from lib389.config import Config +from lib389 import DirSrv, Entry +from lib389.topologies import topology_m4 as topo +from lib389.replica import Replicas + +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__) + +USER_CN="user" + +def add_user(server, no, desc='dummy', sleep=True): + cn = '%s%d' % (USER_CN, no) + dn = 'cn=%s,ou=people,%s' % (cn, SUFFIX) + log.fatal('Adding user (%s): ' % dn) + server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'inetuser', 'userSecurityInformation'], + 'sn': ['_%s' % cn], + 'description': [desc]}))) + time.sleep(1) + +def check_user(server, no, timeout=10): + + cn = '%s%d' % (USER_CN, no) + dn = 'cn=%s,ou=people,%s' % (cn, SUFFIX) + found = False + cpt = 0 + while cpt < timeout: + try: + server.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)") + found = True + break + except ldap.NO_SUCH_OBJECT: + time.sleep(1) + cpt += 1 + return found + +def pattern_errorlog(server, log_pattern): + file_obj = open(server.errlog, "r") + + found = None + # Use a while true iteration because 'for line in file: hit a + while True: + line = file_obj.readline() + found = log_pattern.search(line) + if ((line == '') or (found)): + break + + return found + +def fractional_server_to_replica(server, replica): + server_to_replica = server.agreement.list(suffix=SUFFIX, consumer_host=replica.host, consumer_port=replica.port) + server.modify_s(server_to_replica[0].dn, + [(ldap.MOD_REPLACE, + 'nsDS5ReplicatedAttributeListTotal', + '(objectclass=*) $ EXCLUDE telephoneNumber'), + (ldap.MOD_REPLACE, + 'nsDS5ReplicatedAttributeList', + '(objectclass=*) $ EXCLUDE telephoneNumber'), + (ldap.MOD_REPLACE, 'nsds5ReplicaStripAttrs', + 'modifiersname modifytimestamp')]) + + +def do_skipped_update(server, no): + cn = '%s%d' % (USER_CN, no) + dn = 'cn=%s,ou=people,%s' % (cn, SUFFIX) + for i in range(110): + server.modify_s(dn, [(ldap.MOD_REPLACE, 'telephoneNumber', str(i))]) + +def count_pattern_accesslog(server, log_pattern): + file_obj = open(server.accesslog, "r") + + count = 0 + # Use a while true iteration because 'for line in file: hit a + while True: + line = file_obj.readline() + if (log_pattern.search(line)): + count = count + 1 + if ((line == '')): + break + file_obj.close() + + return count + +def test_ticket_49463(topo): + """Specify a test case purpose or name here + + :id: d1aa2e8b-e6ab-4fc6-9c63-c6f622544f2d + :setup: Fill in set up configuration here + :steps: + 1. Enable fractional replication + 2. Enable replication logging + 3. Check that replication is working fine + 4. Generate skipped updates to create keep alive entries + 5. Remove M3 from the topology + 6. issue cleanAllRuv FORCE that will run on M1 then propagated M2 and M4 + 7. Check that Number DEL keep alive '3' is <= 1 + 8. Check M1 is the originator of cleanAllRuv and M2/M4 the propagated ones + 9. Check replication M1,M2 and M4 can recover + 10. Remove M4 from the topology + 11. Issue cleanAllRuv not force while M2 is stopped (that hangs the cleanAllRuv) + 12. Check that nsds5ReplicaCleanRUV is correctly encoded on M1 (last value: 1) + 13. Check that nsds5ReplicaCleanRUV encoding survives M1 restart + 14. Check that nsds5ReplicaCleanRUV encoding is valid on M2 (last value: 0) + 15. Check that (for M4 cleanAllRUV) M1 is Originator and M2 propagation + :expectedresults: + 1. No report of failure when the RUV is updated + """ + + # Step 1 - Configure fractional (skip telephonenumber) replication + M1 = topo.ms["master1"] + M2 = topo.ms["master2"] + M3 = topo.ms["master3"] + M4 = topo.ms["master4"] + fractional_server_to_replica(M1, M2) + fractional_server_to_replica(M1, M3) + fractional_server_to_replica(M1, M4) + + fractional_server_to_replica(M2, M1) + fractional_server_to_replica(M2, M3) + fractional_server_to_replica(M2, M4) + + fractional_server_to_replica(M3, M1) + fractional_server_to_replica(M3, M2) + fractional_server_to_replica(M3, M4) + + fractional_server_to_replica(M4, M1) + fractional_server_to_replica(M4, M2) + fractional_server_to_replica(M4, M3) + for i in (M1, M2, M3, M4): + i.restart() + + + # Step 2 - enable internal op logging and replication debug + for i in (M1, M2, M3, M4): + i.config.loglevel(vals=[256 + 4], service='access') + i.config.loglevel(vals=[LOG_REPLICA, LOG_DEFAULT], service='error') + + # Step 3 - Check that replication is working fine + add_user(M1, 11, desc="add to M1") + add_user(M2, 21, desc="add to M2") + add_user(M3, 31, desc="add to M3") + add_user(M4, 41, desc="add to M4") + + for i in (M1, M2, M3, M4): + assert check_user(i, 11) + assert check_user(i, 21) + assert check_user(i, 31) + assert check_user(i, 41) + + + # Step 4 - Generate skipped updates to create keep alive entries + for i in (M1, M2, M3, M4): + do_skipped_update(i, 11) + + time.sleep(10) + + # Step 5 - Remove M3 from the topology + M3.stop() + M1.agreement.delete(suffix=SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + M2.agreement.delete(suffix=SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + M4.agreement.delete(suffix=SUFFIX, consumer_host=M3.host, consumer_port=M3.port) + + time.sleep(10) + + # Step 6 - Then issue cleanAllRuv FORCE that will run on M1, M2 and M4 + M1.tasks.cleanAllRUV(suffix=SUFFIX, replicaid='3', + force=True, args={TASK_WAIT: True}) + + # Step 7 - Count the number of received DEL of the keep alive 3 + time.sleep(20) + for i in (M1, M2, M4): + i.restart() + time.sleep(20) + regex = re.compile(".*DEL dn=.cn=repl keep alive 3.*") + for i in (M1, M2, M4): + count = count_pattern_accesslog(M1, regex) + log.debug("count on %s = %d" % (i, count)) + + # check that DEL is replicated once (If DEL is kept in the fix) + # check that DEL is is not replicated (If DEL is finally no long done in the fix) + assert ((count == 1) or (count == 0)) + + # Step 8 - Check that M1 is Originator of cleanAllRuv and M2, M4 propagation + regex = re.compile(".*Original task deletes Keep alive entry .3.*") + assert pattern_errorlog(M1, regex) + + regex = re.compile(".*Propagated task does not delete Keep alive entry .3.*") + assert pattern_errorlog(M2, regex) + assert pattern_errorlog(M4, regex) + + # Step 9 - Check replication M1,M2 and M4 can recover + add_user(M1, 12, desc="add to M1") + add_user(M2, 22, desc="add to M2") + for i in (M1, M2, M4): + assert check_user(i, 12) + assert check_user(i, 22) + + # Step 10 - Remove M4 from the topology + M4.stop() + M1.agreement.delete(suffix=SUFFIX, consumer_host=M4.host, consumer_port=M4.port) + M2.agreement.delete(suffix=SUFFIX, consumer_host=M4.host, consumer_port=M4.port) + + # Step 11 - Issue cleanAllRuv not force while M2 is stopped (that hangs the cleanAllRuv) + M2.stop() + time.sleep(5) + M1.tasks.cleanAllRUV(suffix=SUFFIX, replicaid='4', + force=False, args={TASK_WAIT: False}) + time.sleep(5) + + # Step 12 + # CleanAllRuv is hanging waiting for M2 to restart + # Check that nsds5ReplicaCleanRUV is correctly encoded on M1 + replica = Replicas(M1) + entry = M1.getEntry(replica.get_dn(SUFFIX), ldap.SCOPE_BASE, "(objectclass=*)", ['nsds5ReplicaCleanRUV']) + assert entry.hasAttr('nsds5ReplicaCleanRUV') + + log.info("M1: nsds5ReplicaCleanRUV=%s" % entry.getValue('nsds5ReplicaCleanRUV')) + regex = re.compile("^4:.*:no:1$") + assert regex.match(entry.getValue('nsds5ReplicaCleanRUV')) + + # Step 13 + # Check that it encoding survives restart + M1.restart() + entry = M1.getEntry(replica.get_dn(SUFFIX), ldap.SCOPE_BASE, "(objectclass=*)", ['nsds5ReplicaCleanRUV']) + assert entry.hasAttr('nsds5ReplicaCleanRUV') + assert regex.match(entry.getValue('nsds5ReplicaCleanRUV')) + + # Step 14 - Check that nsds5ReplicaCleanRUV encoding is valid on M2 + M1.stop() + replica = Replicas(M2) + M2.start() + M1.start() + attempt = 0 + while attempt <= 20: + entry = M2.getEntry(replica.get_dn(SUFFIX), ldap.SCOPE_BASE, "(objectclass=*)", ['nsds5ReplicaCleanRUV']) + if entry.hasAttr('nsds5ReplicaCleanRUV'): + break; + attempt = attempt + 1 + time.sleep(1) + + if entry.hasAttr('nsds5ReplicaCleanRUV'): + log.info("M2: nsds5ReplicaCleanRUV=%s" % entry.getValue('nsds5ReplicaCleanRUV')) + regex = re.compile("^4:.*:no:0$") + assert regex.match(entry.getValue('nsds5ReplicaCleanRUV')) + + + # time to run cleanAllRuv + time.sleep(30) + + # Step 15 - Check that M1 is Originator of cleanAllRuv and M2 propagation + regex = re.compile(".*Original task deletes Keep alive entry .4.*") + assert pattern_errorlog(M1, regex) + + regex = re.compile(".*Propagated task does not delete Keep alive entry .4.*") + assert pattern_errorlog(M2, regex) + + + + # 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 + + +if __name__ == '__main__': + # Run isolated + # -s for DEBUG mode + CURRENT_FILE = os.path.realpath(__file__) + pytest.main("-s %s" % CURRENT_FILE) + -- 2.13.6