ticket47973_test.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import os
  2. import sys
  3. import time
  4. import ldap
  5. import ldap.sasl
  6. import logging
  7. import socket
  8. import pytest
  9. from lib389 import DirSrv, Entry, tools, tasks
  10. from lib389.tools import DirSrvTools
  11. from lib389._constants import *
  12. from lib389.properties import *
  13. from lib389.tasks import *
  14. from constants import *
  15. log = logging.getLogger(__name__)
  16. installation_prefix = None
  17. USER_DN = 'uid=user1,%s' % (DEFAULT_SUFFIX)
  18. SCHEMA_RELOAD_COUNT = 10
  19. class TopologyStandalone(object):
  20. def __init__(self, standalone):
  21. standalone.open()
  22. self.standalone = standalone
  23. @pytest.fixture(scope="module")
  24. def topology(request):
  25. '''
  26. This fixture is used to standalone topology for the 'module'.
  27. At the beginning, It may exists a standalone instance.
  28. It may also exists a backup for the standalone instance.
  29. Principle:
  30. If standalone instance exists:
  31. restart it
  32. If backup of standalone exists:
  33. create/rebind to standalone
  34. restore standalone instance from backup
  35. else:
  36. Cleanup everything
  37. remove instance
  38. remove backup
  39. Create instance
  40. Create backup
  41. '''
  42. global installation_prefix
  43. if installation_prefix:
  44. args_instance[SER_DEPLOYED_DIR] = installation_prefix
  45. standalone = DirSrv(verbose=False)
  46. # Args for the standalone instance
  47. args_instance[SER_HOST] = HOST_STANDALONE
  48. args_instance[SER_PORT] = PORT_STANDALONE
  49. args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
  50. args_standalone = args_instance.copy()
  51. standalone.allocate(args_standalone)
  52. # Get the status of the backups
  53. backup_standalone = standalone.checkBackupFS()
  54. # Get the status of the instance and restart it if it exists
  55. instance_standalone = standalone.exists()
  56. if instance_standalone:
  57. # assuming the instance is already stopped, just wait 5 sec max
  58. standalone.stop(timeout=5)
  59. standalone.start(timeout=10)
  60. if backup_standalone:
  61. # The backup exist, assuming it is correct
  62. # we just re-init the instance with it
  63. if not instance_standalone:
  64. standalone.create()
  65. # Used to retrieve configuration information (dbdir, confdir...)
  66. standalone.open()
  67. # restore standalone instance from backup
  68. standalone.stop(timeout=10)
  69. standalone.restoreFS(backup_standalone)
  70. standalone.start(timeout=10)
  71. else:
  72. # We should be here only in two conditions
  73. # - This is the first time a test involve standalone instance
  74. # - Something weird happened (instance/backup destroyed)
  75. # so we discard everything and recreate all
  76. # Remove the backup. So even if we have a specific backup file
  77. # (e.g backup_standalone) we clear backup that an instance may have created
  78. if backup_standalone:
  79. standalone.clearBackupFS()
  80. # Remove the instance
  81. if instance_standalone:
  82. standalone.delete()
  83. # Create the instance
  84. standalone.create()
  85. # Used to retrieve configuration information (dbdir, confdir...)
  86. standalone.open()
  87. # Time to create the backups
  88. standalone.stop(timeout=10)
  89. standalone.backupfile = standalone.backupFS()
  90. standalone.start(timeout=10)
  91. # clear the tmp directory
  92. standalone.clearTmpDir(__file__)
  93. #
  94. # Here we have standalone instance up and running
  95. # Either coming from a backup recovery
  96. # or from a fresh (re)init
  97. # Time to return the topology
  98. return TopologyStandalone(standalone)
  99. def task_complete(conn, task_dn):
  100. finished = False
  101. try:
  102. task_entry = conn.search_s(task_dn, ldap.SCOPE_BASE, 'objectclass=*')
  103. if not task_entry:
  104. log.fatal('wait_for_task: Search failed to find task: ' + task_dn)
  105. assert False
  106. if task_entry[0].hasAttr('nstaskexitcode'):
  107. # task is done
  108. finished = True
  109. except ldap.LDAPError, e:
  110. log.fatal('wait_for_task: Search failed: ' + e.message['desc'])
  111. assert False
  112. return finished
  113. def test_ticket47973(topology):
  114. """
  115. During the schema reload task there is a small window where the new schema is not loaded
  116. into the asi hashtables - this results in searches not returning entries.
  117. """
  118. log.info('Testing Ticket 47973 - Test the searches still work as expected during schema reload tasks')
  119. #
  120. # Add a user
  121. #
  122. try:
  123. topology.standalone.add_s(Entry((USER_DN, {
  124. 'objectclass': 'top extensibleObject'.split(),
  125. 'uid': 'user1'
  126. })))
  127. except ldap.LDAPError, e:
  128. log.error('Failed to add user1: error ' + e.message['desc'])
  129. assert False
  130. #
  131. # Run a series of schema_reload tasks while searching for our user. Since
  132. # this is a race condition, run it several times.
  133. #
  134. task_count = 0
  135. while task_count < SCHEMA_RELOAD_COUNT:
  136. #
  137. # Add a schema reload task
  138. #
  139. TASK_DN = 'cn=task-' + str(task_count) + ',cn=schema reload task, cn=tasks, cn=config'
  140. try:
  141. topology.standalone.add_s(Entry((TASK_DN, {
  142. 'objectclass': 'top extensibleObject'.split(),
  143. 'cn': 'task-' + str(task_count)
  144. })))
  145. except ldap.LDAPError, e:
  146. log.error('Failed to add task entry: error ' + e.message['desc'])
  147. assert False
  148. #
  149. # While we wait for the task to complete keep searching for our user
  150. #
  151. search_count = 0
  152. while search_count < 100:
  153. #
  154. # Now check the user is still being returned
  155. #
  156. try:
  157. entries = topology.standalone.search_s(DEFAULT_SUFFIX,
  158. ldap.SCOPE_SUBTREE,
  159. '(uid=user1)')
  160. if not entries or not entries[0]:
  161. log.fatal('User was not returned from search!')
  162. assert False
  163. except ldap.LDAPError, e:
  164. log.fatal('Unable to search for entry %s: error %s' % (USER_DN, e.message['desc']))
  165. assert False
  166. #
  167. # Check if task is complete
  168. #
  169. if task_complete(topology.standalone, TASK_DN):
  170. break
  171. search_count += 1
  172. task_count += 1
  173. # If we got here the test passed
  174. log.info('Test PASSED')
  175. def test_ticket47973_final(topology):
  176. topology.standalone.delete()
  177. def run_isolated():
  178. '''
  179. run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
  180. To run isolated without py.test, you need to
  181. - edit this file and comment '@pytest.fixture' line before 'topology' function.
  182. - set the installation prefix
  183. - run this program
  184. '''
  185. global installation_prefix
  186. installation_prefix = None
  187. topo = topology(True)
  188. test_ticket47973(topo)
  189. test_ticket47973_final(topo)
  190. if __name__ == '__main__':
  191. run_isolated()