ticket47931_test.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import os
  2. import sys
  3. import time
  4. import ldap
  5. import logging
  6. import pytest
  7. import threading
  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 lib389.utils import *
  14. logging.getLogger(__name__).setLevel(logging.DEBUG)
  15. log = logging.getLogger(__name__)
  16. installation1_prefix = None
  17. SECOND_SUFFIX = "dc=deadlock"
  18. SECOND_BACKEND = "deadlock"
  19. RETROCL_PLUGIN_DN = ('cn=' + PLUGIN_RETRO_CHANGELOG + ',cn=plugins,cn=config')
  20. MEMBEROF_PLUGIN_DN = ('cn=' + PLUGIN_MEMBER_OF + ',cn=plugins,cn=config')
  21. GROUP_DN = ("cn=group," + DEFAULT_SUFFIX)
  22. MEMBER_DN_COMP = "uid=member"
  23. TIME_OUT = 5
  24. class TopologyStandalone(object):
  25. def __init__(self, standalone):
  26. standalone.open()
  27. self.standalone = standalone
  28. class modifySecondBackendThread(threading.Thread):
  29. def __init__(self, inst, timeout):
  30. threading.Thread.__init__(self)
  31. self.daemon = True
  32. self.inst = inst
  33. self.timeout = timeout
  34. def run(self):
  35. conn = self.inst.openConnection()
  36. conn.set_option(ldap.OPT_TIMEOUT, self.timeout)
  37. log.info('Modify second suffix...')
  38. for x in range(0, 5000):
  39. try:
  40. conn.modify_s(SECOND_SUFFIX,
  41. [(ldap.MOD_REPLACE,
  42. 'description',
  43. 'new description')])
  44. except ldap.LDAPError as e:
  45. log.fatal('Failed to modify second suffix - error: %s' %
  46. (e.message['desc']))
  47. assert False
  48. conn.close()
  49. log.info('Finished modifying second suffix')
  50. @pytest.fixture(scope="module")
  51. def topology(request):
  52. global installation1_prefix
  53. if installation1_prefix:
  54. args_instance[SER_DEPLOYED_DIR] = installation1_prefix
  55. # Creating standalone instance ...
  56. standalone = DirSrv(verbose=False)
  57. args_instance[SER_HOST] = HOST_STANDALONE
  58. args_instance[SER_PORT] = PORT_STANDALONE
  59. args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
  60. args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
  61. args_standalone = args_instance.copy()
  62. standalone.allocate(args_standalone)
  63. instance_standalone = standalone.exists()
  64. if instance_standalone:
  65. standalone.delete()
  66. standalone.create()
  67. standalone.open()
  68. # Delete each instance in the end
  69. def fin():
  70. standalone.delete()
  71. request.addfinalizer(fin)
  72. # Clear out the tmp dir
  73. standalone.clearTmpDir(__file__)
  74. return TopologyStandalone(standalone)
  75. def test_ticket47931(topology):
  76. """Test Retro Changelog and MemberOf deadlock fix.
  77. Verification steps:
  78. - Enable retro cl and memberOf.
  79. - Create two backends: A & B.
  80. - Configure retrocl scoping for backend A.
  81. - Configure memberOf plugin for uniquemember
  82. - Create group in backend A.
  83. - In parallel, add members to the group on A, and make modifications
  84. to entries in backend B.
  85. - Make sure the server does not hang during the updates to both
  86. backends.
  87. """
  88. # Enable dynamic plugins to make plugin configuration easier
  89. try:
  90. topology.standalone.modify_s(DN_CONFIG,
  91. [(ldap.MOD_REPLACE,
  92. 'nsslapd-dynamic-plugins',
  93. 'on')])
  94. except ldap.LDAPError as e:
  95. ldap.error('Failed to enable dynamic plugins! ' + e.message['desc'])
  96. assert False
  97. # Enable the plugins
  98. topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF)
  99. topology.standalone.plugins.enable(name=PLUGIN_RETRO_CHANGELOG)
  100. # Create second backend
  101. topology.standalone.backend.create(SECOND_SUFFIX, {BACKEND_NAME: SECOND_BACKEND})
  102. topology.standalone.mappingtree.create(SECOND_SUFFIX, bename=SECOND_BACKEND)
  103. # Create the root node of the second backend
  104. try:
  105. topology.standalone.add_s(Entry((SECOND_SUFFIX,
  106. {'objectclass': 'top domain'.split(),
  107. 'dc': 'deadlock'})))
  108. except ldap.LDAPError as e:
  109. log.fatal('Failed to create suffix entry: error ' + e.message['desc'])
  110. assert False
  111. # Configure retrocl scope
  112. try:
  113. topology.standalone.modify_s(RETROCL_PLUGIN_DN,
  114. [(ldap.MOD_REPLACE,
  115. 'nsslapd-include-suffix',
  116. DEFAULT_SUFFIX)])
  117. except ldap.LDAPError as e:
  118. ldap.error('Failed to configure retrocl plugin: ' + e.message['desc'])
  119. assert False
  120. # Configure memberOf group attribute
  121. try:
  122. topology.standalone.modify_s(MEMBEROF_PLUGIN_DN,
  123. [(ldap.MOD_REPLACE,
  124. 'memberofgroupattr',
  125. 'uniquemember')])
  126. except ldap.LDAPError as e:
  127. log.fatal('Failed to configure memberOf plugin: error ' + e.message['desc'])
  128. assert False
  129. # Create group
  130. try:
  131. topology.standalone.add_s(Entry((GROUP_DN,
  132. {'objectclass': 'top extensibleObject'.split(),
  133. 'cn': 'group'})))
  134. except ldap.LDAPError as e:
  135. log.fatal('Failed to add grouo: error ' + e.message['desc'])
  136. assert False
  137. # Create 1500 entries (future members of the group)
  138. for idx in range(1, 1500):
  139. try:
  140. USER_DN = ("uid=member%d,%s" % (idx, DEFAULT_SUFFIX))
  141. topology.standalone.add_s(Entry((USER_DN,
  142. {'objectclass': 'top extensibleObject'.split(),
  143. 'uid': 'member%d' % (x)})))
  144. except ldap.LDAPError as e:
  145. log.fatal('Failed to add user (%s): error %s' % (USER_DN, e.message['desc']))
  146. assert False
  147. # Modify second backend (separate thread)
  148. mod_backend_thrd = modifySecondBackendThread(topology.standalone, TIME_OUT)
  149. mod_backend_thrd.start()
  150. # Add members to the group - set timeout
  151. log.info('Adding members to the group...')
  152. topology.standalone.set_option(ldap.OPT_TIMEOUT, TIME_OUT)
  153. for idx in range(1, 1500):
  154. try:
  155. MEMBER_VAL = ("uid=member%d,%s" % (idx, DEFAULT_SUFFIX))
  156. topology.standalone.modify_s(GROUP_DN,
  157. [(ldap.MOD_ADD,
  158. 'uniquemember',
  159. MEMBER_VAL)])
  160. except ldap.TIMEOUT:
  161. log.fatal('Deadlock! Bug verification failed.')
  162. assert False
  163. except ldap.LDAPError as e:
  164. log.fatal('Failed to update group(not a deadlock) member (%s) - error: %s' %
  165. (MEMBER_VAL, e.message['desc']))
  166. assert False
  167. log.info('Finished adding members to the group.')
  168. # Wait for the thread to finish
  169. mod_backend_thrd.join()
  170. # No timeout, test passed!
  171. log.info('Test complete\n')
  172. if __name__ == '__main__':
  173. # Run isolated
  174. # -s for DEBUG mode
  175. CURRENT_FILE = os.path.realpath(__file__)
  176. pytest.main("-s %s" % CURRENT_FILE)