ticket47781_test.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import os
  2. import sys
  3. import time
  4. import ldap
  5. import logging
  6. import socket
  7. import pytest
  8. from lib389 import DirSrv, Entry, tools, tasks
  9. from lib389.tools import DirSrvTools
  10. from lib389._constants import *
  11. from lib389.properties import *
  12. from lib389.tasks import *
  13. from constants import *
  14. log = logging.getLogger(__name__)
  15. installation_prefix = None
  16. class TopologyStandalone(object):
  17. def __init__(self, standalone):
  18. standalone.open()
  19. self.standalone = standalone
  20. @pytest.fixture(scope="module")
  21. def topology(request):
  22. '''
  23. This fixture is used to standalone topology for the 'module'.
  24. At the beginning, It may exists a standalone instance.
  25. It may also exists a backup for the standalone instance.
  26. Principle:
  27. If standalone instance exists:
  28. restart it
  29. If backup of standalone exists:
  30. create/rebind to standalone
  31. restore standalone instance from backup
  32. else:
  33. Cleanup everything
  34. remove instance
  35. remove backup
  36. Create instance
  37. Create backup
  38. '''
  39. global installation_prefix
  40. if installation_prefix:
  41. args_instance[SER_DEPLOYED_DIR] = installation_prefix
  42. standalone = DirSrv(verbose=False)
  43. # Args for the standalone instance
  44. args_instance[SER_HOST] = HOST_STANDALONE
  45. args_instance[SER_PORT] = PORT_STANDALONE
  46. args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
  47. args_standalone = args_instance.copy()
  48. standalone.allocate(args_standalone)
  49. # Get the status of the backups
  50. backup_standalone = standalone.checkBackupFS()
  51. # Get the status of the instance and restart it if it exists
  52. instance_standalone = standalone.exists()
  53. if instance_standalone:
  54. # assuming the instance is already stopped, just wait 5 sec max
  55. standalone.stop(timeout=5)
  56. standalone.start(timeout=10)
  57. if backup_standalone:
  58. # The backup exist, assuming it is correct
  59. # we just re-init the instance with it
  60. if not instance_standalone:
  61. standalone.create()
  62. # Used to retrieve configuration information (dbdir, confdir...)
  63. standalone.open()
  64. # restore standalone instance from backup
  65. standalone.stop(timeout=10)
  66. standalone.restoreFS(backup_standalone)
  67. standalone.start(timeout=10)
  68. else:
  69. # We should be here only in two conditions
  70. # - This is the first time a test involve standalone instance
  71. # - Something weird happened (instance/backup destroyed)
  72. # so we discard everything and recreate all
  73. # Remove the backup. So even if we have a specific backup file
  74. # (e.g backup_standalone) we clear backup that an instance may have created
  75. if backup_standalone:
  76. standalone.clearBackupFS()
  77. # Remove the instance
  78. if instance_standalone:
  79. standalone.delete()
  80. # Create the instance
  81. standalone.create()
  82. # Used to retrieve configuration information (dbdir, confdir...)
  83. standalone.open()
  84. # Time to create the backups
  85. standalone.stop(timeout=10)
  86. standalone.backupfile = standalone.backupFS()
  87. standalone.start(timeout=10)
  88. # clear the tmp directory
  89. standalone.clearTmpDir(__file__)
  90. #
  91. # Here we have standalone instance up and running
  92. # Either coming from a backup recovery
  93. # or from a fresh (re)init
  94. # Time to return the topology
  95. return TopologyStandalone(standalone)
  96. def test_ticket47781(topology):
  97. """
  98. Testing for a deadlock after doing an online import of an LDIF with
  99. replication data. The replication agreement should be invalid.
  100. """
  101. log.info('Testing Ticket 47781 - Testing for deadlock after importing LDIF with replication data')
  102. #
  103. # Setup Replication
  104. #
  105. log.info('Setting up replication...')
  106. topology.standalone.replica.enableReplication(suffix=DEFAULT_SUFFIX, role=REPLICAROLE_MASTER,
  107. replicaId=REPLICAID_MASTER_1)
  108. properties = {RA_NAME: r'meTo_$host:$port',
  109. RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
  110. RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
  111. RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
  112. RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
  113. # The agreement should point to a server that does NOT exist (invalid port)
  114. repl_agreement = topology.standalone.agreement.create(suffix=DEFAULT_SUFFIX,
  115. host=topology.standalone.host,
  116. port=5555,
  117. properties=properties)
  118. #
  119. # add two entries
  120. #
  121. log.info('Adding two entries...')
  122. try:
  123. topology.standalone.add_s(Entry(('cn=entry1,dc=example,dc=com', {
  124. 'objectclass': 'top person'.split(),
  125. 'sn': 'user',
  126. 'cn': 'entry1'})))
  127. except ldap.LDAPError, e:
  128. log.error('Failed to add entry 1: ' + e.message['desc'])
  129. assert False
  130. try:
  131. topology.standalone.add_s(Entry(('cn=entry2,dc=example,dc=com', {
  132. 'objectclass': 'top person'.split(),
  133. 'sn': 'user',
  134. 'cn': 'entry2'})))
  135. except ldap.LDAPError, e:
  136. log.error('Failed to add entry 2: ' + e.message['desc'])
  137. assert False
  138. #
  139. # export the replication ldif
  140. #
  141. log.info('Exporting replication ldif...')
  142. args = {EXPORT_REPL_INFO: True}
  143. exportTask = Tasks(topology.standalone)
  144. try:
  145. exportTask.exportLDIF(DEFAULT_SUFFIX, None, "/tmp/export.ldif", args)
  146. except ValueError:
  147. assert False
  148. #
  149. # Restart the server
  150. #
  151. log.info('Restarting server...')
  152. topology.standalone.stop(timeout=5)
  153. topology.standalone.start(timeout=5)
  154. #
  155. # Import the ldif
  156. #
  157. log.info('Import replication LDIF file...')
  158. importTask = Tasks(topology.standalone)
  159. args = {TASK_WAIT: True}
  160. try:
  161. importTask.importLDIF(DEFAULT_SUFFIX, None, "/tmp/export.ldif", args)
  162. os.remove("/tmp/export.ldif")
  163. except ValueError:
  164. os.remove("/tmp/export.ldif")
  165. assert False
  166. #
  167. # Search for tombstones - we should not hang/timeout
  168. #
  169. log.info('Search for tombstone entries(should find one and not hang)...')
  170. topology.standalone.set_option(ldap.OPT_NETWORK_TIMEOUT, 5)
  171. topology.standalone.set_option(ldap.OPT_TIMEOUT, 5)
  172. try:
  173. entries = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 'objectclass=nsTombstone')
  174. if not entries:
  175. log.fatal('Search failed to find any entries.')
  176. assert PR_False
  177. except ldap.LDAPError, e:
  178. log.fatal('Search failed: ' + e.message['desc'])
  179. assert PR_False
  180. # If we got here we passed!
  181. log.info('Ticket47781 Test - Passed')
  182. def test_ticket47781_final(topology):
  183. topology.standalone.delete()
  184. def run_isolated():
  185. '''
  186. run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
  187. To run isolated without py.test, you need to
  188. - edit this file and comment '@pytest.fixture' line before 'topology' function.
  189. - set the installation prefix
  190. - run this program
  191. '''
  192. global installation_prefix
  193. installation_prefix = None
  194. topo = topology(True)
  195. test_ticket47781(topo)
  196. test_ticket47781_final(topo)
  197. if __name__ == '__main__':
  198. run_isolated()