ticket47619_test.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. '''
  2. Created on Nov 7, 2013
  3. @author: tbordaz
  4. '''
  5. import os
  6. import sys
  7. import time
  8. import ldap
  9. import logging
  10. import socket
  11. import time
  12. import logging
  13. import pytest
  14. import re
  15. from lib389 import DirSrv, Entry, tools
  16. from lib389.tools import DirSrvTools
  17. from lib389._constants import *
  18. from lib389.properties import *
  19. from constants import *
  20. logging.getLogger(__name__).setLevel(logging.DEBUG)
  21. log = logging.getLogger(__name__)
  22. installation_prefix = None
  23. TEST_REPL_DN = "cn=test_repl, %s" % SUFFIX
  24. ENTRY_DN = "cn=test_entry, %s" % SUFFIX
  25. OTHER_NAME = 'other_entry'
  26. MAX_OTHERS = 100
  27. ATTRIBUTES = [ 'street', 'countryName', 'description', 'postalAddress', 'postalCode', 'title', 'l', 'roomNumber' ]
  28. class TopologyMasterConsumer(object):
  29. def __init__(self, master, consumer):
  30. master.open()
  31. self.master = master
  32. consumer.open()
  33. self.consumer = consumer
  34. def __repr__(self):
  35. return "Master[%s] -> Consumer[%s" % (self.master, self.consumer)
  36. @pytest.fixture(scope="module")
  37. def topology(request):
  38. '''
  39. This fixture is used to create a replicated topology for the 'module'.
  40. The replicated topology is MASTER -> Consumer.
  41. At the beginning, It may exists a master instance and/or a consumer instance.
  42. It may also exists a backup for the master and/or the consumer.
  43. Principle:
  44. If master instance exists:
  45. restart it
  46. If consumer instance exists:
  47. restart it
  48. If backup of master AND backup of consumer exists:
  49. create or rebind to consumer
  50. create or rebind to master
  51. restore master from backup
  52. restore consumer from backup
  53. else:
  54. Cleanup everything
  55. remove instances
  56. remove backups
  57. Create instances
  58. Initialize replication
  59. Create backups
  60. '''
  61. global installation_prefix
  62. if installation_prefix:
  63. args_instance[SER_DEPLOYED_DIR] = installation_prefix
  64. master = DirSrv(verbose=False)
  65. consumer = DirSrv(verbose=False)
  66. # Args for the master instance
  67. args_instance[SER_HOST] = HOST_MASTER
  68. args_instance[SER_PORT] = PORT_MASTER
  69. args_instance[SER_SERVERID_PROP] = SERVERID_MASTER
  70. args_master = args_instance.copy()
  71. master.allocate(args_master)
  72. # Args for the consumer instance
  73. args_instance[SER_HOST] = HOST_CONSUMER
  74. args_instance[SER_PORT] = PORT_CONSUMER
  75. args_instance[SER_SERVERID_PROP] = SERVERID_CONSUMER
  76. args_consumer = args_instance.copy()
  77. consumer.allocate(args_consumer)
  78. # Get the status of the backups
  79. backup_master = master.checkBackupFS()
  80. backup_consumer = consumer.checkBackupFS()
  81. # Get the status of the instance and restart it if it exists
  82. instance_master = master.exists()
  83. if instance_master:
  84. master.stop(timeout=10)
  85. master.start(timeout=10)
  86. instance_consumer = consumer.exists()
  87. if instance_consumer:
  88. consumer.stop(timeout=10)
  89. consumer.start(timeout=10)
  90. if backup_master and backup_consumer:
  91. # The backups exist, assuming they are correct
  92. # we just re-init the instances with them
  93. if not instance_master:
  94. master.create()
  95. # Used to retrieve configuration information (dbdir, confdir...)
  96. master.open()
  97. if not instance_consumer:
  98. consumer.create()
  99. # Used to retrieve configuration information (dbdir, confdir...)
  100. consumer.open()
  101. # restore master from backup
  102. master.stop(timeout=10)
  103. master.restoreFS(backup_master)
  104. master.start(timeout=10)
  105. # restore consumer from backup
  106. consumer.stop(timeout=10)
  107. consumer.restoreFS(backup_consumer)
  108. consumer.start(timeout=10)
  109. else:
  110. # We should be here only in two conditions
  111. # - This is the first time a test involve master-consumer
  112. # so we need to create everything
  113. # - Something weird happened (instance/backup destroyed)
  114. # so we discard everything and recreate all
  115. # Remove all the backups. So even if we have a specific backup file
  116. # (e.g backup_master) we clear all backups that an instance my have created
  117. if backup_master:
  118. master.clearBackupFS()
  119. if backup_consumer:
  120. consumer.clearBackupFS()
  121. # Remove all the instances
  122. if instance_master:
  123. master.delete()
  124. if instance_consumer:
  125. consumer.delete()
  126. # Create the instances
  127. master.create()
  128. master.open()
  129. consumer.create()
  130. consumer.open()
  131. #
  132. # Now prepare the Master-Consumer topology
  133. #
  134. # First Enable replication
  135. master.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER)
  136. consumer.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_CONSUMER)
  137. # Initialize the supplier->consumer
  138. properties = {RA_NAME: r'meTo_$host:$port',
  139. RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
  140. RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
  141. RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
  142. RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
  143. repl_agreement = master.agreement.create(suffix=SUFFIX, host=consumer.host, port=consumer.port, properties=properties)
  144. if not repl_agreement:
  145. log.fatal("Fail to create a replica agreement")
  146. sys.exit(1)
  147. log.debug("%s created" % repl_agreement)
  148. master.agreement.init(SUFFIX, HOST_CONSUMER, PORT_CONSUMER)
  149. master.waitForReplInit(repl_agreement)
  150. # Check replication is working fine
  151. master.add_s(Entry((TEST_REPL_DN, {
  152. 'objectclass': "top person".split(),
  153. 'sn': 'test_repl',
  154. 'cn': 'test_repl'})))
  155. loop = 0
  156. while loop <= 10:
  157. try:
  158. ent = consumer.getEntry(TEST_REPL_DN, ldap.SCOPE_BASE, "(objectclass=*)")
  159. break
  160. except ldap.NO_SUCH_OBJECT:
  161. time.sleep(1)
  162. loop += 1
  163. # Time to create the backups
  164. master.stop(timeout=10)
  165. master.backupfile = master.backupFS()
  166. master.start(timeout=10)
  167. consumer.stop(timeout=10)
  168. consumer.backupfile = consumer.backupFS()
  169. consumer.start(timeout=10)
  170. # clear the tmp directory
  171. master.clearTmpDir(__file__)
  172. #
  173. # Here we have two instances master and consumer
  174. # with replication working. Either coming from a backup recovery
  175. # or from a fresh (re)init
  176. # Time to return the topology
  177. return TopologyMasterConsumer(master, consumer)
  178. def test_ticket47619_init(topology):
  179. """
  180. Initialize the test environment
  181. """
  182. topology.master.plugins.enable(name=PLUGIN_RETRO_CHANGELOG)
  183. #topology.master.plugins.enable(name=PLUGIN_MEMBER_OF)
  184. #topology.master.plugins.enable(name=PLUGIN_REFER_INTEGRITY)
  185. topology.master.stop(timeout=10)
  186. topology.master.start(timeout=10)
  187. topology.master.log.info("test_ticket47619_init topology %r" % (topology))
  188. # the test case will check if a warning message is logged in the
  189. # error log of the supplier
  190. topology.master.errorlog_file = open(topology.master.errlog, "r")
  191. # add dummy entries
  192. for cpt in range(MAX_OTHERS):
  193. name = "%s%d" % (OTHER_NAME, cpt)
  194. topology.master.add_s(Entry(("cn=%s,%s" % (name, SUFFIX), {
  195. 'objectclass': "top person".split(),
  196. 'sn': name,
  197. 'cn': name})))
  198. topology.master.log.info("test_ticket47619_init: %d entries ADDed %s[0..%d]" % (MAX_OTHERS, OTHER_NAME, MAX_OTHERS-1))
  199. # Check the number of entries in the retro changelog
  200. time.sleep(2)
  201. ents = topology.master.search_s(RETROCL_SUFFIX, ldap.SCOPE_ONELEVEL, "(objectclass=*)")
  202. assert len(ents) == MAX_OTHERS
  203. def test_ticket47619_create_index(topology):
  204. args = {INDEX_TYPE: 'eq'}
  205. for attr in ATTRIBUTES:
  206. topology.master.index.create(suffix=RETROCL_SUFFIX, attr=attr, args=args)
  207. def test_ticket47619_reindex(topology):
  208. '''
  209. Reindex all the attributes in ATTRIBUTES
  210. '''
  211. args = {TASK_WAIT: True}
  212. for attr in ATTRIBUTES:
  213. rc = topology.master.tasks.reindex(suffix=RETROCL_SUFFIX, attrname=attr, args=args)
  214. assert rc == 0
  215. def test_ticket47619_check_indexed_search(topology):
  216. for attr in ATTRIBUTES:
  217. ents = topology.master.search_s(RETROCL_SUFFIX, ldap.SCOPE_SUBTREE, "(%s=hello)" % attr)
  218. assert len(ents) == 0
  219. def test_ticket47619_final(topology):
  220. topology.master.stop(timeout=10)
  221. topology.consumer.stop(timeout=10)
  222. def run_isolated():
  223. '''
  224. run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
  225. To run isolated without py.test, you need to
  226. - edit this file and comment '@pytest.fixture' line before 'topology' function.
  227. - set the installation prefix
  228. - run this program
  229. '''
  230. global installation_prefix
  231. installation_prefix = None
  232. topo = topology(True)
  233. test_ticket47619_init(topo)
  234. test_ticket47619_create_index(topo)
  235. # important restart that trigger the hang
  236. # at restart, finding the new 'changelog' backend, the backend is acquired in Read
  237. # preventing the reindex task to complete
  238. topo.master.restart(timeout=10)
  239. test_ticket47619_reindex(topo)
  240. test_ticket47619_check_indexed_search(topo)
  241. test_ticket47619_final(topo)
  242. if __name__ == '__main__':
  243. run_isolated()