1
0

test_dynamic_plugins.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. '''
  2. Created on Dec 09, 2014
  3. @author: mreynolds
  4. '''
  5. import os
  6. import sys
  7. import time
  8. import ldap
  9. import ldap.sasl
  10. import logging
  11. import pytest
  12. import plugin_tests
  13. import stress_tests
  14. from lib389 import DirSrv, Entry, tools, tasks
  15. from lib389.tools import DirSrvTools
  16. from lib389._constants import *
  17. from lib389.properties import *
  18. from lib389.tasks import *
  19. log = logging.getLogger(__name__)
  20. installation_prefix = None
  21. class TopologyStandalone(object):
  22. def __init__(self, standalone):
  23. standalone.open()
  24. self.standalone = standalone
  25. def repl_fail(replica):
  26. # remove replica instance, and assert failure
  27. replica.delete()
  28. assert False
  29. @pytest.fixture(scope="module")
  30. def topology(request):
  31. '''
  32. This fixture is used to standalone topology for the 'module'.
  33. '''
  34. global installation_prefix
  35. if installation_prefix:
  36. args_instance[SER_DEPLOYED_DIR] = installation_prefix
  37. standalone = DirSrv(verbose=False)
  38. # Args for the standalone instance
  39. args_instance[SER_HOST] = HOST_STANDALONE
  40. args_instance[SER_PORT] = PORT_STANDALONE
  41. args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
  42. args_standalone = args_instance.copy()
  43. standalone.allocate(args_standalone)
  44. # Get the status of the instance and restart it if it exists
  45. instance_standalone = standalone.exists()
  46. # Remove the instance
  47. if instance_standalone:
  48. standalone.delete()
  49. # Create the instance
  50. standalone.create()
  51. # Used to retrieve configuration information (dbdir, confdir...)
  52. standalone.open()
  53. # Here we have standalone instance up and running
  54. return TopologyStandalone(standalone)
  55. def test_dynamic_plugins(topology):
  56. """
  57. Test Dynamic Plugins - exercise each plugin and its main features, while
  58. changing the configuration without restarting the server.
  59. Need to test: functionality, stability, and stress. These tests need to run
  60. with replication disabled, and with replication setup with a
  61. second instance. Then test if replication is working, and we have
  62. same entries on each side.
  63. Functionality - Make sure that as configuration changes are made they take
  64. effect immediately. Cross plugin interaction (e.g. automember/memberOf)
  65. needs to tested, as well as plugin tasks. Need to test plugin
  66. config validation(dependencies, etc).
  67. Memory Corruption - Restart the plugins many times, and in different orders and test
  68. functionality, and stability. This will excerise the internal
  69. plugin linked lists, dse callbacks, and task handlers.
  70. Stress - Put the server under load that will trigger multiple plugins(MO, RI, DNA, etc)
  71. Restart various plugins while these operations are going on. Perform this test
  72. 5 times(stress_max_run).
  73. """
  74. REPLICA_PORT = 33334
  75. RUV_FILTER = '(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))'
  76. master_maxcsn = 0
  77. replica_maxcsn = 0
  78. msg = ' (no replication)'
  79. replication_run = False
  80. stress_max_runs = 5
  81. # First enable dynamic plugins
  82. try:
  83. topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-dynamic-plugins', 'on')])
  84. except ldap.LDAPError, e:
  85. ldap.fatal('Failed to enable dynamic plugin!' + e.message['desc'])
  86. assert False
  87. # Test that critical plugins can be updated even though the change might not be applied
  88. try:
  89. topology.standalone.modify_s(DN_LDBM, [(ldap.MOD_REPLACE, 'description', 'test')])
  90. except ldap.LDAPError, e:
  91. ldap.fatal('Failed to apply change to critical plugin' + e.message['desc'])
  92. assert False
  93. while 1:
  94. #
  95. # First run the tests with replication disabled, then rerun them with replication set up
  96. #
  97. ############################################################################
  98. # Test plugin functionality
  99. ############################################################################
  100. log.info('####################################################################')
  101. log.info('Testing Dynamic Plugins Functionality' + msg + '...')
  102. log.info('####################################################################\n')
  103. plugin_tests.test_all_plugins(topology.standalone)
  104. log.info('####################################################################')
  105. log.info('Successfully Tested Dynamic Plugins Functionality' + msg + '.')
  106. log.info('####################################################################\n')
  107. ############################################################################
  108. # Test the stability by exercising the internal lists, callabcks, and task handlers
  109. ############################################################################
  110. log.info('####################################################################')
  111. log.info('Testing Dynamic Plugins for Memory Corruption' + msg + '...')
  112. log.info('####################################################################\n')
  113. prev_plugin_test = None
  114. prev_prev_plugin_test = None
  115. for plugin_test in plugin_tests.func_tests:
  116. #
  117. # Restart the plugin several times (and prev plugins) - work that linked list
  118. #
  119. plugin_test(topology.standalone, "restart")
  120. if prev_prev_plugin_test:
  121. prev_prev_plugin_test(topology.standalone, "restart")
  122. plugin_test(topology.standalone, "restart")
  123. if prev_plugin_test:
  124. prev_plugin_test(topology.standalone, "restart")
  125. plugin_test(topology.standalone, "restart")
  126. # Now run the functional test
  127. plugin_test(topology.standalone)
  128. # Set the previous tests
  129. if prev_plugin_test:
  130. prev_prev_plugin_test = prev_plugin_test
  131. prev_plugin_test = plugin_test
  132. log.info('####################################################################')
  133. log.info('Successfully Tested Dynamic Plugins for Memory Corruption' + msg + '.')
  134. log.info('####################################################################\n')
  135. ############################################################################
  136. # Stress two plugins while restarting it, and while restarting other plugins.
  137. # The goal is to not crash, and have the plugins work after stressing them.
  138. ############################################################################
  139. log.info('####################################################################')
  140. log.info('Stressing Dynamic Plugins' + msg + '...')
  141. log.info('####################################################################\n')
  142. stress_tests.configureMO(topology.standalone)
  143. stress_tests.configureRI(topology.standalone)
  144. stress_count = 0
  145. while stress_count < stress_max_runs:
  146. log.info('####################################################################')
  147. log.info('Running stress test' + msg + '. Run (%d/%d)...' % (stress_count + 1, stress_max_runs))
  148. log.info('####################################################################\n')
  149. try:
  150. # Launch three new threads to add a bunch of users
  151. add_users = stress_tests.AddUsers(topology.standalone, 'employee', True)
  152. add_users.start()
  153. add_users2 = stress_tests.AddUsers(topology.standalone, 'entry', True)
  154. add_users2.start()
  155. add_users3 = stress_tests.AddUsers(topology.standalone, 'person', True)
  156. add_users3.start()
  157. time.sleep(1)
  158. # While we are adding users restart the MO plugin and an idle plugin
  159. topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF)
  160. topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF)
  161. time.sleep(1)
  162. topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF)
  163. time.sleep(1)
  164. topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF)
  165. topology.standalone.plugins.disable(name=PLUGIN_LINKED_ATTRS)
  166. topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS)
  167. time.sleep(1)
  168. topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF)
  169. topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF)
  170. time.sleep(2)
  171. topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF)
  172. time.sleep(1)
  173. topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF)
  174. topology.standalone.plugins.disable(name=PLUGIN_LINKED_ATTRS)
  175. topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS)
  176. topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF)
  177. time.sleep(1)
  178. topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF)
  179. topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF)
  180. topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF)
  181. # Wait for the 'adding' threads to complete
  182. add_users.join()
  183. add_users2.join()
  184. add_users3.join()
  185. # Now launch three threads to delete the users
  186. del_users = stress_tests.DelUsers(topology.standalone, 'employee')
  187. del_users.start()
  188. del_users2 = stress_tests.DelUsers(topology.standalone, 'entry')
  189. del_users2.start()
  190. del_users3 = stress_tests.DelUsers(topology.standalone, 'person')
  191. del_users3.start()
  192. time.sleep(1)
  193. # Restart both the MO, RI plugins during these deletes, and an idle plugin
  194. topology.standalone.plugins.disable(name=PLUGIN_REFER_INTEGRITY)
  195. topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF)
  196. topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF)
  197. topology.standalone.plugins.enable(name=PLUGIN_REFER_INTEGRITY)
  198. time.sleep(1)
  199. topology.standalone.plugins.disable(name=PLUGIN_REFER_INTEGRITY)
  200. time.sleep(1)
  201. topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF)
  202. time.sleep(1)
  203. topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF)
  204. time.sleep(1)
  205. topology.standalone.plugins.enable(name=PLUGIN_REFER_INTEGRITY)
  206. topology.standalone.plugins.disable(name=PLUGIN_LINKED_ATTRS)
  207. topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS)
  208. topology.standalone.plugins.disable(name=PLUGIN_REFER_INTEGRITY)
  209. topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF)
  210. topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF)
  211. topology.standalone.plugins.enable(name=PLUGIN_REFER_INTEGRITY)
  212. time.sleep(2)
  213. topology.standalone.plugins.disable(name=PLUGIN_REFER_INTEGRITY)
  214. time.sleep(1)
  215. topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF)
  216. time.sleep(1)
  217. topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF)
  218. time.sleep(1)
  219. topology.standalone.plugins.enable(name=PLUGIN_REFER_INTEGRITY)
  220. topology.standalone.plugins.disable(name=PLUGIN_LINKED_ATTRS)
  221. topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS)
  222. # Wait for the 'deleting' threads to complete
  223. del_users.join()
  224. del_users2.join()
  225. del_users3.join()
  226. # Now make sure both the MO and RI plugins still work correctly
  227. plugin_tests.func_tests[8](topology.standalone) # RI plugin
  228. plugin_tests.func_tests[5](topology.standalone) # MO plugin
  229. # Cleanup the stress tests
  230. stress_tests.cleanup(topology.standalone)
  231. except:
  232. log.info('Stress test failed!')
  233. repl_fail(replica_inst)
  234. stress_count += 1
  235. log.info('####################################################################')
  236. log.info('Successfully Stressed Dynamic Plugins' + msg +
  237. '. Completed (%d/%d)' % (stress_count, stress_max_runs))
  238. log.info('####################################################################\n')
  239. if replication_run:
  240. # We're done.
  241. break
  242. else:
  243. #
  244. # Enable replication and run everything one more time
  245. #
  246. log.info('Setting up replication, and rerunning the tests...\n')
  247. # Create replica instance
  248. replica_inst = DirSrv(verbose=False)
  249. args_instance[SER_HOST] = LOCALHOST
  250. args_instance[SER_PORT] = REPLICA_PORT
  251. args_instance[SER_SERVERID_PROP] = 'replica'
  252. args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
  253. args_replica_inst = args_instance.copy()
  254. replica_inst.allocate(args_replica_inst)
  255. replica_inst.create()
  256. replica_inst.open()
  257. try:
  258. topology.standalone.replica.enableReplication(suffix=DEFAULT_SUFFIX,
  259. role=REPLICAROLE_MASTER,
  260. replicaId=1)
  261. replica_inst.replica.enableReplication(suffix=DEFAULT_SUFFIX,
  262. role=REPLICAROLE_CONSUMER,
  263. replicaId=65535)
  264. properties = {RA_NAME: r'to_replica',
  265. RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
  266. RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
  267. RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
  268. RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
  269. repl_agreement = topology.standalone.agreement.create(suffix=DEFAULT_SUFFIX,
  270. host=LOCALHOST,
  271. port=REPLICA_PORT,
  272. properties=properties)
  273. if not repl_agreement:
  274. log.fatal("Fail to create a replica agreement")
  275. repl_fail(replica_inst)
  276. topology.standalone.agreement.init(DEFAULT_SUFFIX, LOCALHOST, REPLICA_PORT)
  277. topology.standalone.waitForReplInit(repl_agreement)
  278. except:
  279. log.info('Failed to setup replication!')
  280. repl_fail(replica_inst)
  281. replication_run = True
  282. msg = ' (replication enabled)'
  283. time.sleep(1)
  284. ############################################################################
  285. # Check replication, and data are in sync, and remove the instance
  286. ############################################################################
  287. log.info('Checking if replication is in sync...')
  288. try:
  289. # Grab master's max CSN
  290. entry = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, RUV_FILTER)
  291. if not entry:
  292. log.error('Failed to find db tombstone entry from master')
  293. repl_fail(replica_inst)
  294. elements = entry[0].getValues('nsds50ruv')
  295. for ruv in elements:
  296. if 'replica 1' in ruv:
  297. parts = ruv.split()
  298. if len(parts) == 5:
  299. master_maxcsn = parts[4]
  300. break
  301. else:
  302. log.error('RUV is incomplete')
  303. repl_fail(replica_inst)
  304. if master_maxcsn == 0:
  305. log.error('Failed to find maxcsn on master')
  306. repl_fail(replica_inst)
  307. except ldap.LDAPError, e:
  308. log.fatal('Unable to search masterfor db tombstone: ' + e.message['desc'])
  309. repl_fail(replica_inst)
  310. # Loop on the consumer - waiting for it to catch up
  311. count = 0
  312. insync = False
  313. while count < 10:
  314. try:
  315. # Grab master's max CSN
  316. entry = replica_inst.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, RUV_FILTER)
  317. if not entry:
  318. log.error('Failed to find db tombstone entry on consumer')
  319. repl_fail(replica_inst)
  320. elements = entry[0].getValues('nsds50ruv')
  321. for ruv in elements:
  322. if 'replica 1' in ruv:
  323. parts = ruv.split()
  324. if len(parts) == 5:
  325. replica_maxcsn = parts[4]
  326. break
  327. if replica_maxcsn == 0:
  328. log.error('Failed to find maxcsn on consumer')
  329. repl_fail(replica_inst)
  330. except ldap.LDAPError, e:
  331. log.fatal('Unable to search for db tombstone on consumer: ' + e.message['desc'])
  332. repl_fail(replica_inst)
  333. if master_maxcsn == replica_maxcsn:
  334. insync = True
  335. log.info('Replication is in sync.\n')
  336. break
  337. count += 1
  338. time.sleep(1)
  339. # Report on replication status
  340. if not insync:
  341. log.error('Consumer not in sync with master!')
  342. repl_fail(replica_inst)
  343. #
  344. # Verify the databases are identical. There should not be any "user, entry, employee" entries
  345. #
  346. log.info('Checking if the data is the same between the replicas...')
  347. # Check the master
  348. try:
  349. entries = topology.standalone.search_s(DEFAULT_SUFFIX,
  350. ldap.SCOPE_SUBTREE,
  351. "(|(uid=person*)(uid=entry*)(uid=employee*))")
  352. if len(entries) > 0:
  353. log.error('Master database has incorrect data set!\n')
  354. repl_fail(replica_inst)
  355. except ldap.LDAPError, e:
  356. log.fatal('Unable to search db on master: ' + e.message['desc'])
  357. repl_fail(replica_inst)
  358. # Check the consumer
  359. try:
  360. entries = replica_inst.search_s(DEFAULT_SUFFIX,
  361. ldap.SCOPE_SUBTREE,
  362. "(|(uid=person*)(uid=entry*)(uid=employee*))")
  363. if len(entries) > 0:
  364. log.error('Consumer database in not consistent with master database')
  365. repl_fail(replica_inst)
  366. except ldap.LDAPError, e:
  367. log.fatal('Unable to search db on consumer: ' + e.message['desc'])
  368. repl_fail(replica_inst)
  369. log.info('Data is consistent across the replicas.\n')
  370. log.info('####################################################################')
  371. log.info('Replication consistency test passed')
  372. log.info('####################################################################\n')
  373. # Remove the replica instance
  374. replica_inst.delete()
  375. ############################################################################
  376. # We made it to the end!
  377. ############################################################################
  378. log.info('#####################################################')
  379. log.info('#####################################################')
  380. log.info("Dynamic Plugins Testsuite: Completed Successfully!")
  381. log.info('#####################################################')
  382. log.info('#####################################################\n')
  383. def test_dynamic_plugins_final(topology):
  384. topology.standalone.delete()
  385. def run_isolated():
  386. '''
  387. run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
  388. To run isolated without py.test, you need to
  389. - edit this file and comment '@pytest.fixture' line before 'topology' function.
  390. - set the installation prefix
  391. - run this program
  392. '''
  393. global installation_prefix
  394. installation_prefix = None
  395. topo = topology(True)
  396. test_dynamic_plugins(topo)
  397. test_dynamic_plugins_final(topo)
  398. if __name__ == '__main__':
  399. run_isolated()