1
0

wait_for_async_feature_test.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. import os
  2. import sys
  3. import time
  4. import ldap
  5. import logging
  6. import pytest
  7. from lib389 import DirSrv, Entry, tools, tasks
  8. from lib389.tools import DirSrvTools
  9. from lib389._constants import *
  10. from lib389.properties import *
  11. from lib389.tasks import *
  12. from lib389.utils import *
  13. from collections import Counter
  14. logging.getLogger(__name__).setLevel(logging.DEBUG)
  15. log = logging.getLogger(__name__)
  16. installation1_prefix = None
  17. WAITFOR_ASYNC_ATTR = "nsDS5ReplicaWaitForAsyncResults"
  18. class TopologyReplication(object):
  19. def __init__(self, master1, master2, m1_m2_agmt, m2_m1_agmt):
  20. master1.open()
  21. master2.open()
  22. self.masters = ((master1, m1_m2_agmt),
  23. (master2, m2_m1_agmt))
  24. @pytest.fixture(scope="module")
  25. def topology(request):
  26. global installation1_prefix
  27. if installation1_prefix:
  28. args_instance[SER_DEPLOYED_DIR] = installation1_prefix
  29. # Creating master 1...
  30. master1 = DirSrv(verbose=False)
  31. args_instance[SER_HOST] = HOST_MASTER_1
  32. args_instance[SER_PORT] = PORT_MASTER_1
  33. args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_1
  34. args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
  35. args_master = args_instance.copy()
  36. master1.allocate(args_master)
  37. instance_master1 = master1.exists()
  38. if instance_master1:
  39. master1.delete()
  40. master1.create()
  41. master1.open()
  42. master1.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_1)
  43. # Creating master 2...
  44. master2 = DirSrv(verbose=False)
  45. args_instance[SER_HOST] = HOST_MASTER_2
  46. args_instance[SER_PORT] = PORT_MASTER_2
  47. args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_2
  48. args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
  49. args_master = args_instance.copy()
  50. master2.allocate(args_master)
  51. instance_master2 = master2.exists()
  52. if instance_master2:
  53. master2.delete()
  54. master2.create()
  55. master2.open()
  56. master2.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_2)
  57. #
  58. # Create all the agreements
  59. #
  60. # Creating agreement from master 1 to master 2
  61. properties = {RA_NAME: r'meTo_$host:$port',
  62. RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
  63. RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
  64. RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
  65. RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
  66. m1_m2_agmt = master1.agreement.create(suffix=SUFFIX, host=master2.host, port=master2.port, properties=properties)
  67. if not m1_m2_agmt:
  68. log.fatal("Fail to create a master -> master replica agreement")
  69. sys.exit(1)
  70. log.debug("%s created" % m1_m2_agmt)
  71. # Creating agreement from master 2 to master 1
  72. properties = {RA_NAME: r'meTo_$host:$port',
  73. RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
  74. RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
  75. RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
  76. RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
  77. m2_m1_agmt = master2.agreement.create(suffix=SUFFIX, host=master1.host, port=master1.port, properties=properties)
  78. if not m2_m1_agmt:
  79. log.fatal("Fail to create a master -> master replica agreement")
  80. sys.exit(1)
  81. log.debug("%s created" % m2_m1_agmt)
  82. # Allow the replicas to get situated with the new agreements...
  83. time.sleep(5)
  84. #
  85. # Initialize all the agreements
  86. #
  87. master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
  88. master1.waitForReplInit(m1_m2_agmt)
  89. master2.agreement.init(SUFFIX, HOST_MASTER_1, PORT_MASTER_1)
  90. master2.waitForReplInit(m2_m1_agmt)
  91. # Check replication is working...
  92. if master1.testReplication(DEFAULT_SUFFIX, master2):
  93. log.info('Replication is working.')
  94. else:
  95. log.fatal('Replication is not working.')
  96. assert False
  97. log.info("Set Replication Debugging loglevel for the errorlog")
  98. master1.setLogLevel(lib389.LOG_REPLICA)
  99. master2.setLogLevel(lib389.LOG_REPLICA)
  100. # Delete each instance in the end
  101. def fin():
  102. master1.delete()
  103. master2.delete()
  104. request.addfinalizer(fin)
  105. # Clear out the tmp dir
  106. master1.clearTmpDir(__file__)
  107. return TopologyReplication(master1, master2, m1_m2_agmt, m2_m1_agmt)
  108. @pytest.fixture(params=[(None, (4, 10)),
  109. ('2000', (0, 1)),
  110. ('0', (4, 10)),
  111. ('-5', (4, 10))])
  112. def waitfor_async_attr(topology, request):
  113. """Sets attribute on all replicas"""
  114. attr_value = request.param[0]
  115. expected_result = request.param[1]
  116. # Run through all masters
  117. for master in topology.masters:
  118. agmt = master[1]
  119. try:
  120. if attr_value:
  121. log.info("Set %s: %s on %s" % (
  122. WAITFOR_ASYNC_ATTR, attr_value, master[0].serverid))
  123. mod = [(ldap.MOD_REPLACE, WAITFOR_ASYNC_ATTR, attr_value)]
  124. else:
  125. log.info("Delete %s from %s" % (
  126. WAITFOR_ASYNC_ATTR, master[0].serverid))
  127. mod = [(ldap.MOD_DELETE, WAITFOR_ASYNC_ATTR, None)]
  128. master[0].modify_s(agmt, mod)
  129. except ldap.LDAPError as e:
  130. log.error('Failed to set or delete %s attribute: (%s)' % (
  131. WAITFOR_ASYNC_ATTR, e.message['desc']))
  132. return (attr_value, expected_result)
  133. @pytest.fixture
  134. def entries(topology, request):
  135. """Adds entries to the master1"""
  136. master1 = topology.masters[0][0]
  137. TEST_OU = "test"
  138. test_dn = SUFFIX
  139. test_list = []
  140. log.info("Add 100 nested entries under replicated suffix on %s" % master1.serverid)
  141. for i in xrange(100):
  142. test_dn = 'ou=%s%s,%s' % (TEST_OU, i, test_dn)
  143. test_list.insert(0, test_dn)
  144. try:
  145. master1.add_s(Entry((test_dn,
  146. {'objectclass': 'top',
  147. 'objectclass': 'organizationalUnit',
  148. 'ou': TEST_OU})))
  149. except ldap.LDAPError as e:
  150. log.error('Failed to add entry (%s): error (%s)' % (test_dn,
  151. e.message['desc']))
  152. assert False
  153. log.info("Delete created entries")
  154. for test_dn in test_list:
  155. try:
  156. master1.delete_s(test_dn)
  157. except ldap.LDAPError, e:
  158. log.error('Failed to delete entry (%s): error (%s)' % (test_dn,
  159. e.message['desc']))
  160. assert False
  161. def fin():
  162. log.info("Clear the errors log in the end of the test case")
  163. with open(master1.errlog, 'w') as errlog:
  164. errlog.writelines("")
  165. request.addfinalizer(fin)
  166. def test_not_int_value(topology):
  167. """Tests not integer value"""
  168. master1 = topology.masters[0][0]
  169. agmt = topology.masters[0][1]
  170. log.info("Try to set %s: wv1" % WAITFOR_ASYNC_ATTR)
  171. try:
  172. mod = [(ldap.MOD_REPLACE, WAITFOR_ASYNC_ATTR, "wv1")]
  173. master1.modify_s(agmt, mod)
  174. except ldap.LDAPError as e:
  175. assert e.message['desc'] == 'Invalid syntax'
  176. def test_multi_value(topology):
  177. """Tests multi value"""
  178. master1 = topology.masters[0][0]
  179. agmt = topology.masters[0][1]
  180. log.info("agmt: %s" % agmt)
  181. log.info("Try to set %s: 100 and 101 in the same time (multi value test)" % (
  182. WAITFOR_ASYNC_ATTR))
  183. try:
  184. mod = [(ldap.MOD_ADD, WAITFOR_ASYNC_ATTR, "100")]
  185. master1.modify_s(agmt, mod)
  186. mod = [(ldap.MOD_ADD, WAITFOR_ASYNC_ATTR, "101")]
  187. master1.modify_s(agmt, mod)
  188. except ldap.LDAPError as e:
  189. assert e.message['desc'] == 'Object class violation'
  190. def test_value_check(topology, waitfor_async_attr):
  191. """Checks that value has been set correctly"""
  192. attr_value = waitfor_async_attr[0]
  193. for master in topology.masters:
  194. agmt = master[1]
  195. log.info("Check attr %s on %s" % (WAITFOR_ASYNC_ATTR, master[0].serverid))
  196. try:
  197. if attr_value:
  198. entry = master[0].search_s(agmt, ldap.SCOPE_BASE, "%s=%s" % (
  199. WAITFOR_ASYNC_ATTR, attr_value))
  200. assert entry
  201. else:
  202. entry = master[0].search_s(agmt, ldap.SCOPE_BASE, "%s=*" % WAITFOR_ASYNC_ATTR)
  203. assert not entry
  204. except ldap.LDAPError as e:
  205. log.fatal('Search failed, error: ' + e.message['desc'])
  206. assert False
  207. def test_behavior_with_value(topology, waitfor_async_attr, entries):
  208. """Tests replication behavior with valid
  209. nsDS5ReplicaWaitForAsyncResults attribute values
  210. """
  211. master1 = topology.masters[0][0]
  212. sync_dict = Counter()
  213. min_ap = waitfor_async_attr[1][0]
  214. max_ap = waitfor_async_attr[1][1]
  215. log.info("Gather all sync attempts within Counter dict, group by timestamp")
  216. with open(master1.errlog, 'r') as errlog:
  217. errlog_filtered = filter(lambda x: "waitfor_async_results" in x, errlog)
  218. for line in errlog_filtered:
  219. # Watch only over unsuccessful sync attempts
  220. if line.split()[4] != line.split()[5]:
  221. timestamp = line.split(']')[0]
  222. sync_dict[timestamp] += 1
  223. log.info("Take the most common timestamp and assert it has appeared " \
  224. "in the range from %s to %s times" % (min_ap, max_ap))
  225. most_common_val = sync_dict.most_common(1)[0][1]
  226. assert min_ap <= most_common_val <= max_ap
  227. if __name__ == '__main__':
  228. # Run isolated
  229. # -s for DEBUG mode
  230. CURRENT_FILE = os.path.realpath(__file__)
  231. pytest.main("-s %s" % CURRENT_FILE)