From c038b581bdcabcc86a33f9a3eae446b684825698 Mon Sep 17 00:00:00 2001 From: Mark Reynolds Date: Tue, 16 Dec 2014 16:44:33 -0500 Subject: [PATCH 52/53] Ticket 47451 - Add Dynamic Plugin CI Suite Description: Add lib389(CI) testsuite for Dynamic Plugins Perform functional tests for plugins that have configuration settings - Restart the plugin - Make condfig change - Test the plugin - Make another config change - Test plugin - Test plugin dependency - Cleanup Perform memory corruption test - This test forces the global plugin linked list, DSE callbacks, and task handlers to be rewritten in various orders while testing all the plugins. Perform Stress tests - Perform a series of operations that engage two plugins. While there operations are being performed restart various plugins. - Verify the server does not crash, and that hte plugins work correctly. https://fedorahosted.org/389/ticket/47451 Reviewed by: nhosoi(Thanks!) (cherry picked from commit 4e39dbbfde56ca68f5a26d0bf2ac3a261234c8cd) (cherry picked from commit 2ace01377aec2872579f9f892361946f1d5b07d2) --- dirsrvtests/suites/dynamic-plugins/constants.py | 33 + dirsrvtests/suites/dynamic-plugins/finalizer.py | 57 + dirsrvtests/suites/dynamic-plugins/plugin_tests.py | 1973 ++++++++++++++++++++ dirsrvtests/suites/dynamic-plugins/stress_tests.py | 133 ++ .../suites/dynamic-plugins/test_dynamic_plugins.py | 315 ++++ 5 files changed, 2511 insertions(+) create mode 100644 dirsrvtests/suites/dynamic-plugins/constants.py create mode 100644 dirsrvtests/suites/dynamic-plugins/finalizer.py create mode 100644 dirsrvtests/suites/dynamic-plugins/plugin_tests.py create mode 100644 dirsrvtests/suites/dynamic-plugins/stress_tests.py create mode 100644 dirsrvtests/suites/dynamic-plugins/test_dynamic_plugins.py diff --git a/dirsrvtests/suites/dynamic-plugins/constants.py b/dirsrvtests/suites/dynamic-plugins/constants.py new file mode 100644 index 0000000..cbc310e --- /dev/null +++ b/dirsrvtests/suites/dynamic-plugins/constants.py @@ -0,0 +1,33 @@ +''' +Created on Dec 09, 2014 + +@author: mreynolds +''' +import os +from lib389 import DN_DM +from lib389._constants import * +from lib389.properties import * + +SUFFIX = 'dc=example,dc=com' +PASSWORD = 'password' + +# Used for standalone topology +HOST_STANDALONE = LOCALHOST +PORT_STANDALONE = 33389 +SERVERID_STANDALONE = 'dynamic-plugins' + +# Each defined instance above must be added in that list +ALL_INSTANCES = [ {SER_HOST: HOST_STANDALONE, SER_PORT: PORT_STANDALONE, SER_SERVERID_PROP: SERVERID_STANDALONE}, + ] +# This is a template +args_instance = { + SER_DEPLOYED_DIR: os.environ.get('PREFIX', None), + SER_BACKUP_INST_DIR: os.environ.get('BACKUPDIR', DEFAULT_BACKUPDIR), + SER_ROOT_DN: DN_DM, + SER_ROOT_PW: PASSWORD, + SER_HOST: LOCALHOST, + SER_PORT: DEFAULT_PORT, + SER_SERVERID_PROP: "template", + SER_CREATION_SUFFIX: DEFAULT_SUFFIX} + + diff --git a/dirsrvtests/suites/dynamic-plugins/finalizer.py b/dirsrvtests/suites/dynamic-plugins/finalizer.py new file mode 100644 index 0000000..eb02332 --- /dev/null +++ b/dirsrvtests/suites/dynamic-plugins/finalizer.py @@ -0,0 +1,57 @@ +''' +Created on Nov 5, 2013 + +@author: tbordaz +''' +import os +import sys +import time +import ldap +import logging +import socket +import time +import logging +import pytest +from lib389 import DirSrv, Entry, tools +from lib389.tools import DirSrvTools +from lib389._constants import DN_DM +from lib389.properties import * +from constants import * + +log = logging.getLogger(__name__) + +global installation_prefix +installation_prefix=os.getenv('PREFIX') + +def test_finalizer(): + global installation_prefix + + # for each defined instance, remove it + for args_instance in ALL_INSTANCES: + if installation_prefix: + # overwrite the environment setting + args_instance[SER_DEPLOYED_DIR] = installation_prefix + + instance = DirSrv(verbose=True) + instance.allocate(args_instance) + if instance.exists(): + instance.delete() + + # remove any existing backup for this instance + instance.clearBackupFS() + +def run_isolated(): + ''' + run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..) + To run isolated without py.test, you need to + - set the installation prefix + - run this program + ''' + global installation_prefix + installation_prefix = None + + test_finalizer() + +if __name__ == '__main__': + run_isolated() + diff --git a/dirsrvtests/suites/dynamic-plugins/plugin_tests.py b/dirsrvtests/suites/dynamic-plugins/plugin_tests.py new file mode 100644 index 0000000..fa88145 --- /dev/null +++ b/dirsrvtests/suites/dynamic-plugins/plugin_tests.py @@ -0,0 +1,1973 @@ +''' +Created on Dec 09, 2014 + +@author: mreynolds +''' +import os +import sys +import time +import ldap +import time +import logging +import socket +import pytest +from lib389 import DirSrv, Entry, tools, tasks +from lib389.tools import DirSrvTools +from lib389._constants import * +from lib389.properties import * +from lib389.tasks import * +from constants import * + +log = logging.getLogger(__name__) + +USER1_DN = 'uid=user1,' + DEFAULT_SUFFIX +USER2_DN = 'uid=user2,' + DEFAULT_SUFFIX +USER3_DN = 'uid=user3,' + DEFAULT_SUFFIX +BUSER1_DN = 'uid=user1,ou=branch1,' + DEFAULT_SUFFIX +BUSER2_DN = 'uid=user2,ou=branch2,' + DEFAULT_SUFFIX +BUSER3_DN = 'uid=user3,ou=branch2,' + DEFAULT_SUFFIX +BRANCH1_DN = 'ou=branch1,' + DEFAULT_SUFFIX +BRANCH2_DN = 'ou=branch2,' + DEFAULT_SUFFIX +GROUP_OU = 'ou=groups,' + DEFAULT_SUFFIX +PEOPLE_OU = 'ou=people,' + DEFAULT_SUFFIX +GROUP_DN = 'cn=group,' + DEFAULT_SUFFIX + +''' + Functional tests for each plugin + + Test: + plugin restarts (test when on and off) + plugin config validation + plugin dependencies + plugin functionality (including plugin tasks) +''' + + +################################################################################ +# +# Test Plugin Dependency +# +################################################################################ +def test_dependency(inst, plugin): + """ + Set the "account usabilty" plugin to depend on this plugin. This plugin + is generic, always enabled, and perfect for our testing + """ + + try: + inst.modify_s('cn=' + PLUGIN_ACCT_USABILITY + ',cn=plugins,cn=config', + [(ldap.MOD_REPLACE, 'nsslapd-plugin-depends-on-named', plugin)]) + + except ldap.LDAPError, e: + log.error('test_dependency: Failed to modify ' + PLUGIN_ACCT_USABILITY + ': error ' + e.message['desc']) + assert False + + try: + inst.modify_s('cn=' + plugin + ',cn=plugins,cn=config', + [(ldap.MOD_REPLACE, 'nsslapd-pluginenabled', 'off')]) + + except ldap.UNWILLING_TO_PERFORM: + # failed as expected + pass + else: + # Incorrectly succeeded + log.error('test_dependency: Plugin dependency check failed (%s)' % plugin) + assert False + + # Now undo the change + try: + inst.modify_s('cn=' + PLUGIN_ACCT_USABILITY + ',cn=plugins,cn=config', + [(ldap.MOD_DELETE, 'nsslapd-plugin-depends-on-named', None)]) + except ldap.LDAPError, e: + log.error('test_dependency: Failed to reset ' + plugin + ': error ' + e.message['desc']) + assert False + + +################################################################################ +# +# Test Account Policy Plugin (0) +# +################################################################################ +def test_acctpolicy(inst, args=None): + # stop the plugin, and start it + inst.plugins.disable(name=PLUGIN_ACCT_POLICY) + inst.plugins.enable(name=PLUGIN_ACCT_POLICY) + + if args == "restart": + return True + + CONFIG_DN = 'cn=config,cn=Account Policy Plugin,cn=plugins,cn=config' + log.info('Testing ' + PLUGIN_ACCT_POLICY + '...') + + ############################################################################ + # Configure plugin + ############################################################################ + + # Add the config entry + try: + inst.add_s(Entry((CONFIG_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'cn': 'config', + 'alwaysrecordlogin': 'yes', + 'stateattrname': 'lastLoginTime' + }))) + except ldap.ALREADY_EXISTS: + try: + inst.modify_s(CONFIG_DN, + [(ldap.MOD_REPLACE, 'alwaysrecordlogin', 'yes'), + (ldap.MOD_REPLACE, 'stateattrname', 'lastLoginTime')]) + except ldap.LDAPError, e: + log.error('test_acctpolicy: Failed to modify config entry: error ' + e.message['desc']) + assert False + except ldap.LDAPError, e: + log.error('test_acctpolicy: Failed to add config entry: error ' + e.message['desc']) + assert False + + # Now set the config entry in the plugin entry + #try: + # inst.modify_s('cn=' + PLUGIN_ACCT_POLICY + ',cn=plugins,cn=config', + # [(ldap.MOD_REPLACE, 'nsslapd-pluginarg0', CONFIG_DN)]) + #except ldap.LDAPError, e: + # log.error('test_acctpolicy: Failed to set config entry in plugin entry: error ' + e.message['desc']) + # assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # !!!! acctpolicy does have have a dse callabck to check for live updates - restart plugin for now !!!! + inst.plugins.disable(name=PLUGIN_ACCT_POLICY) + inst.plugins.enable(name=PLUGIN_ACCT_POLICY) + + # Add an entry + try: + inst.add_s(Entry((USER1_DN, {'objectclass': "top extensibleObject".split(), + 'sn': '1', + 'cn': 'user 1', + 'uid': 'user1', + 'userpassword': 'password'}))) + except ldap.LDAPError, e: + log.error('test_acctpolicy: Failed to add test user' + USER1_DN + ': error ' + e.message['desc']) + assert False + + # bind as user + try: + inst.simple_bind_s(USER1_DN, "password") + except ldap.LDAPError, e: + log.error('test_acctpolicy:Failed to bind as user1: ' + e.message['desc']) + assert False + + # Bind as Root DN + try: + inst.simple_bind_s(DN_DM, PASSWORD) + except ldap.LDAPError, e: + log.error('test_acctpolicy: Failed to bind as rootDN: ' + e.message['desc']) + assert False + + # Check lastLoginTime of USER1 + try: + entries = inst.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 'lastLoginTime=*') + if not entries: + log.fatal('test_acctpolicy: Search failed to find an entry with lastLoginTime.') + assert False + except ldap.LDAPError, e: + log.fatal('test_acctpolicy: Search failed: ' + e.message['desc']) + assert False + + ############################################################################ + # Change config - change the stateAttrName to a new attribute + ############################################################################ + + try: + inst.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'stateattrname', 'testLastLoginTime')]) + + except ldap.LDAPError, e: + log.error('test_acctpolicy: Failed to modify config entry: error ' + e.message['desc']) + assert False + + # !!!! must restart for now !!!!! + inst.plugins.disable(name=PLUGIN_ACCT_POLICY) + inst.plugins.enable(name=PLUGIN_ACCT_POLICY) + + ############################################################################ + # Test plugin + ############################################################################ + + # login as user + try: + inst.simple_bind_s(USER1_DN, "password") + except ldap.LDAPError, e: + log.error('test_acctpolicy: Failed to bind(2nd) as user1: ' + e.message['desc']) + assert False + + # Bind as Root DN + try: + inst.simple_bind_s(DN_DM, PASSWORD) + except ldap.LDAPError, e: + log.error('test_acctpolicy: Failed to bind as rootDN: ' + e.message['desc']) + assert False + + # Check testLastLoginTime was added to USER1 + try: + entries = inst.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(testLastLoginTime=*)') + if not entries: + log.fatal('test_acctpolicy: Search failed to find an entry with testLastLoginTime.') + assert False + except ldap.LDAPError, e: + log.fatal('test_acctpolicy: Search failed: ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin dependency + ############################################################################ + + test_dependency(inst, PLUGIN_ACCT_POLICY) + + ############################################################################ + # Cleanup + ############################################################################ + + try: + inst.delete_s(USER1_DN) + except ldap.LDAPError, e: + log.error('test_acctpolicy: Failed to delete test entry: ' + e.message['desc']) + assert False + + ############################################################################ + # Test passed + ############################################################################ + + log.info('test_acctpolicy: PASS\n') + + return + + +################################################################################ +# +# Test Attribute Uniqueness Plugin (1) +# +################################################################################ +def test_attruniq(inst, args=None): + # stop the plugin, and start it + inst.plugins.disable(name=PLUGIN_ATTR_UNIQUENESS) + inst.plugins.enable(name=PLUGIN_ATTR_UNIQUENESS) + + if args == "restart": + return + + log.info('Testing ' + PLUGIN_ATTR_UNIQUENESS + '...') + + ############################################################################ + # Configure plugin + ############################################################################ + + try: + inst.modify_s('cn=' + PLUGIN_ATTR_UNIQUENESS + ',cn=plugins,cn=config', + [(ldap.MOD_REPLACE, 'uniqueness-attribute-name', 'uid')]) + + except ldap.LDAPError, e: + log.error('test_attruniq: Failed to configure plugin for "uid": error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # Add an entry + try: + inst.add_s(Entry((USER1_DN, {'objectclass': "top extensibleObject".split(), + 'sn': '1', + 'cn': 'user 1', + 'uid': 'user1', + 'mail': 'user1@example.com', + 'userpassword': 'password'}))) + except ldap.LDAPError, e: + log.error('test_attruniq: Failed to add test user' + USER1_DN + ': error ' + e.message['desc']) + assert False + + # Add an entry with a duplicate "uid" + try: + inst.add_s(Entry((USER2_DN, {'objectclass': "top extensibleObject".split(), + 'sn': '2', + 'cn': 'user 2', + 'uid': 'user2', + 'uid': 'user1', + 'userpassword': 'password'}))) + + except ldap.CONSTRAINT_VIOLATION: + pass + else: + log.error('test_attruniq: Adding of 2nd entry(uid) incorrectly succeeded') + assert False + + ############################################################################ + # Change config to use "mail" instead of "uid" + ############################################################################ + + try: + inst.modify_s('cn=' + PLUGIN_ATTR_UNIQUENESS + ',cn=plugins,cn=config', + [(ldap.MOD_REPLACE, 'uniqueness-attribute-name', 'mail')]) + + except ldap.LDAPError, e: + log.error('test_attruniq: Failed to configure plugin for "mail": error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin - Add an entry, that has a duplicate "mail" value + ############################################################################ + + try: + inst.add_s(Entry((USER2_DN, {'objectclass': "top extensibleObject".split(), + 'sn': '2', + 'cn': 'user 2', + 'uid': 'user2', + 'mail': 'user1@example.com', + 'userpassword': 'password'}))) + except ldap.CONSTRAINT_VIOLATION: + pass + else: + log.error('test_attruniq: Adding of 2nd entry(mail) incorrectly succeeded') + assert False + + ############################################################################ + # Test plugin dependency + ############################################################################ + + test_dependency(inst, PLUGIN_ATTR_UNIQUENESS) + + ############################################################################ + # Cleanup + ############################################################################ + + try: + inst.delete_s(USER1_DN) + except ldap.LDAPError, e: + log.error('test_attruniq: Failed to delete test entry: ' + e.message['desc']) + assert False + + ############################################################################ + # Test passed + ############################################################################ + + log.info('test_attruniq: PASS\n') + return + + +################################################################################ +# +# Test Auto Membership Plugin (2) +# +################################################################################ +def test_automember(inst, args=None): + # stop the plugin, and start it + inst.plugins.disable(name=PLUGIN_AUTOMEMBER) + inst.plugins.enable(name=PLUGIN_AUTOMEMBER) + + if args == "restart": + return + + CONFIG_DN = 'cn=config,cn=' + PLUGIN_AUTOMEMBER + ',cn=plugins,cn=config' + + log.info('Testing ' + PLUGIN_AUTOMEMBER + '...') + + ############################################################################ + # Configure plugin + ############################################################################ + + # Add the automember group + try: + inst.add_s(Entry((GROUP_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'cn': 'group' + }))) + except ldap.LDAPError, e: + log.error('test_automember: Failed to add group: error ' + e.message['desc']) + assert False + + # Add ou=branch1 + try: + inst.add_s(Entry((BRANCH1_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'ou': 'branch1' + }))) + except ldap.LDAPError, e: + log.error('test_automember: Failed to add branch1: error ' + e.message['desc']) + assert False + + # Add ou=branch2 + try: + inst.add_s(Entry((BRANCH2_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'ou': 'branch2' + }))) + except ldap.LDAPError, e: + log.error('test_automember: Failed to add branch2: error ' + e.message['desc']) + assert False + + # Add the automember config entry + try: + inst.add_s(Entry((CONFIG_DN, { + 'objectclass': 'top autoMemberDefinition'.split(), + 'cn': 'config', + 'autoMemberScope': 'ou=branch1,' + DEFAULT_SUFFIX, + 'autoMemberFilter': 'objectclass=top', + 'autoMemberDefaultGroup': 'cn=group,' + DEFAULT_SUFFIX, + 'autoMemberGroupingAttr': 'member:dn' + }))) + except ldap.LDAPError, e: + log.error('test_automember: Failed to add config entry: error ' + e.message['desc']) + assert False + + ############################################################################ + # Test the plugin + ############################################################################ + + # Add a user that should get added to the group + try: + inst.add_s(Entry((BUSER1_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user1' + }))) + except ldap.LDAPError, e: + log.error('test_automember: Failed to add user: error ' + e.message['desc']) + assert False + + # Check the group + try: + entries = inst.search_s(GROUP_DN, ldap.SCOPE_BASE, + '(member=' + BUSER1_DN + ')') + if not entries: + log.fatal('test_automember: Search failed to find member user1') + assert False + except ldap.LDAPError, e: + log.fatal('test_automember: Search failed: ' + e.message['desc']) + assert False + + ############################################################################ + # Change config + ############################################################################ + + try: + inst.modify_s(CONFIG_DN, + [(ldap.MOD_REPLACE, 'autoMemberGroupingAttr', 'uniquemember:dn'), + (ldap.MOD_REPLACE, 'autoMemberScope', 'ou=branch2,' + DEFAULT_SUFFIX)]) + + except ldap.LDAPError, e: + log.error('test_automember: Failed to modify config entry: error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # Add a user that should get added to the group + try: + inst.add_s(Entry((BUSER2_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user2' + }))) + except ldap.LDAPError, e: + log.error('test_automember: Failed to user to branch2: error ' + e.message['desc']) + assert False + + # Check the group + try: + entries = inst.search_s(GROUP_DN, ldap.SCOPE_BASE, + '(uniquemember=' + BUSER2_DN + ')') + if not entries: + log.fatal('test_automember: Search failed to find uniquemember user2') + assert False + except ldap.LDAPError, e: + log.fatal('test_automember: Search failed: ' + e.message['desc']) + assert False + + ############################################################################ + # Test Task + ############################################################################ + + # Disable plugin + inst.plugins.disable(name=PLUGIN_AUTOMEMBER) + + # Add an entry that should be picked up by automember - verify it is not(yet) + try: + inst.add_s(Entry((BUSER3_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user3' + }))) + except ldap.LDAPError, e: + log.error('test_automember: Failed to user3 to branch2: error ' + e.message['desc']) + assert False + + # Check the group - uniquemember sahould not exist + try: + entries = inst.search_s(GROUP_DN, ldap.SCOPE_BASE, + '(uniquemember=' + BUSER3_DN + ')') + if entries: + log.fatal('test_automember: user3 was incorrectly added to the group') + assert False + except ldap.LDAPError, e: + log.fatal('test_automember: Search failed: ' + e.message['desc']) + assert False + + # Enable plugin + inst.plugins.enable(name=PLUGIN_AUTOMEMBER) + + # Add the task + try: + inst.add_s(Entry(('cn=task-' + str(int(time.time())) + ',cn=automember rebuild membership,cn=tasks,cn=config', { + 'objectclass': 'top extensibleObject'.split(), + 'basedn': 'ou=branch2,' + DEFAULT_SUFFIX, + 'filter': 'objectclass=top'}))) + except ldap.LDAPError, e: + log.error('test_automember: Failed to add task: error ' + e.message['desc']) + assert False + + time.sleep(3) # Wait for the task to do its work + + # Verify the fixup task worked + try: + entries = inst.search_s(GROUP_DN, ldap.SCOPE_BASE, + '(uniquemember=' + BUSER3_DN + ')') + if not entries: + log.fatal('test_automember: user3 was not added to the group') + assert False + except ldap.LDAPError, e: + log.fatal('test_automember: Search failed: ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin dependency + ############################################################################ + + test_dependency(inst, PLUGIN_AUTOMEMBER) + + ############################################################################ + # Cleanup + ############################################################################ + + try: + inst.delete_s(BUSER1_DN) + except ldap.LDAPError, e: + log.error('test_automember: Failed to delete test entry1: ' + e.message['desc']) + assert False + + try: + inst.delete_s(BUSER2_DN) + except ldap.LDAPError, e: + log.error('test_automember: Failed to delete test entry2: ' + e.message['desc']) + assert False + + try: + inst.delete_s(BUSER3_DN) + except ldap.LDAPError, e: + log.error('test_automember: Failed to delete test entry3: ' + e.message['desc']) + assert False + + try: + inst.delete_s(BRANCH1_DN) + except ldap.LDAPError, e: + log.error('test_automember: Failed to delete branch1: ' + e.message['desc']) + assert False + + try: + inst.delete_s(BRANCH2_DN) + except ldap.LDAPError, e: + log.error('test_automember: Failed to delete test branch2: ' + e.message['desc']) + assert False + + try: + inst.delete_s(GROUP_DN) + except ldap.LDAPError, e: + log.error('test_automember: Failed to delete test group: ' + e.message['desc']) + assert False + + try: + inst.delete_s(CONFIG_DN) + except ldap.LDAPError, e: + log.error('test_automember: Failed to delete plugin config entry: ' + e.message['desc']) + assert False + + ############################################################################ + # Test passed + ############################################################################ + + log.info('test_automember: PASS\n') + return + + +################################################################################ +# +# Test DNA Plugin (3) +# +################################################################################ +def test_dna(inst, args=None): + # stop the plugin, and start it + inst.plugins.disable(name=PLUGIN_DNA) + inst.plugins.enable(name=PLUGIN_DNA) + + if args == "restart": + return + + CONFIG_DN = 'cn=config,cn=' + PLUGIN_DNA + ',cn=plugins,cn=config' + + log.info('Testing ' + PLUGIN_DNA + '...') + + ############################################################################ + # Configure plugin + ############################################################################ + + try: + inst.add_s(Entry((CONFIG_DN, { + 'objectclass': 'top dnaPluginConfig'.split(), + 'cn': 'config', + 'dnatype': 'uidNumber', + 'dnafilter': '(objectclass=top)', + 'dnascope': DEFAULT_SUFFIX, + 'dnaMagicRegen': '-1', + 'dnaMaxValue': '50000', + 'dnaNextValue': '1' + }))) + except ldap.ALREADY_EXISTS: + try: + inst.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'dnaNextValue', '1'), + (ldap.MOD_REPLACE, 'dnaMagicRegen', '-1')]) + except ldap.LDAPError, e: + log.error('test_dna: Failed to set the DNA plugin: error ' + e.message['desc']) + assert False + except ldap.LDAPError, e: + log.error('test_dna: Failed to add config entry: error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + try: + inst.add_s(Entry((USER1_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user1' + }))) + except ldap.LDAPError, e: + log.error('test_dna: Failed to user1: error ' + e.message['desc']) + assert False + + # See if the entry now has the new uidNumber assignment - uidNumber=1 + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(uidNumber=1)') + if not entries: + log.fatal('test_dna: user1 was not updated - (looking for uidNumber: 1)') + assert False + except ldap.LDAPError, e: + log.fatal('test_dna: Search for user1 failed: ' + e.message['desc']) + assert False + + # Test the magic regen value + try: + inst.modify_s(USER1_DN, [(ldap.MOD_REPLACE, 'uidNumber', '-1')]) + except ldap.LDAPError, e: + log.error('test_dna: Failed to set the magic reg value: error ' + e.message['desc']) + assert False + + # See if the entry now has the new uidNumber assignment - uidNumber=2 + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(uidNumber=2)') + if not entries: + log.fatal('test_dna: user1 was not updated (looking for uidNumber: 2)') + assert False + except ldap.LDAPError, e: + log.fatal('test_dna: Search for user1 failed: ' + e.message['desc']) + assert False + + ################################################################################ + # Change the config + ################################################################################ + + try: + inst.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'dnaMagicRegen', '-2')]) + except ldap.LDAPError, e: + log.error('test_dna: Failed to set the magic reg value to -2: error ' + e.message['desc']) + assert False + + ################################################################################ + # Test plugin + ################################################################################ + + # Test the magic regen value + try: + inst.modify_s(USER1_DN, [(ldap.MOD_REPLACE, 'uidNumber', '-2')]) + except ldap.LDAPError, e: + log.error('test_dna: Failed to set the magic reg value: error ' + e.message['desc']) + assert False + + # See if the entry now has the new uidNumber assignment - uidNumber=3 + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(uidNumber=3)') + if not entries: + log.fatal('test_dna: user1 was not updated (looking for uidNumber: 3)') + assert False + except ldap.LDAPError, e: + log.fatal('test_dna: Search for user1 failed: ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin dependency + ############################################################################ + + test_dependency(inst, PLUGIN_AUTOMEMBER) + + ############################################################################ + # Cleanup + ############################################################################ + + try: + inst.delete_s(USER1_DN) + except ldap.LDAPError, e: + log.error('test_automember: Failed to delete test entry1: ' + e.message['desc']) + assert False + + inst.plugins.disable(name=PLUGIN_DNA) + + ############################################################################ + # Test passed + ############################################################################ + + log.info('test_dna: PASS\n') + + return + + +################################################################################ +# +# Test Linked Attrs Plugin (4) +# +################################################################################ +def test_linkedattrs(inst, args=None): + # stop the plugin, and start it + inst.plugins.disable(name=PLUGIN_LINKED_ATTRS) + inst.plugins.enable(name=PLUGIN_LINKED_ATTRS) + + if args == "restart": + return + + CONFIG_DN = 'cn=config,cn=' + PLUGIN_LINKED_ATTRS + ',cn=plugins,cn=config' + + log.info('Testing ' + PLUGIN_LINKED_ATTRS + '...') + + ############################################################################ + # Configure plugin + ############################################################################ + + # Add test entries + try: + inst.add_s(Entry((USER1_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user1' + }))) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to user1: error ' + e.message['desc']) + assert False + + try: + inst.add_s(Entry((USER2_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user2' + }))) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to user1: error ' + e.message['desc']) + assert False + + # Add the linked attrs config entry + try: + inst.add_s(Entry((CONFIG_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'cn': 'config', + 'linkType': 'directReport', + 'managedType': 'manager' + }))) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to add config entry: error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # Set "directReport" should add "manager" to the other entry + try: + inst.modify_s(USER1_DN, [(ldap.MOD_REPLACE, 'directReport', USER2_DN)]) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to add "directReport" to user1: error ' + e.message['desc']) + assert False + + # See if manager was added to the other entry + try: + entries = inst.search_s(USER2_DN, ldap.SCOPE_BASE, '(manager=*)') + if not entries: + log.fatal('test_linkedattrs: user2 missing "manager" attribute') + assert False + except ldap.LDAPError, e: + log.fatal('test_linkedattrs: Search for user1 failed: ' + e.message['desc']) + assert False + + # Remove "directReport" should remove "manager" to the other entry + try: + inst.modify_s(USER1_DN, [(ldap.MOD_DELETE, 'directReport', None)]) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to delete directReport: error ' + e.message['desc']) + assert False + + # See if manager was removed + try: + entries = inst.search_s(USER2_DN, ldap.SCOPE_BASE, '(manager=*)') + if entries: + log.fatal('test_linkedattrs: user2 "manager" attribute not removed') + assert False + except ldap.LDAPError, e: + log.fatal('test_linkedattrs: Search for user1 failed: ' + e.message['desc']) + assert False + + ############################################################################ + # Change the config - using linkType "indirectReport" now + ############################################################################ + + try: + inst.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'linkType', 'indirectReport')]) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to set linkTypee: error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # Make sure the old linkType(directManager) is not working + try: + inst.modify_s(USER1_DN, [(ldap.MOD_REPLACE, 'directReport', USER2_DN)]) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to add "directReport" to user1: error ' + e.message['desc']) + assert False + + # See if manager was added to the other entry, better not be... + try: + entries = inst.search_s(USER2_DN, ldap.SCOPE_BASE, '(manager=*)') + if entries: + log.fatal('test_linkedattrs: user2 had "manager" added unexpectedly') + assert False + except ldap.LDAPError, e: + log.fatal('test_linkedattrs: Search for user2 failed: ' + e.message['desc']) + assert False + + # Now, set the new linkType "indirectReport", which should add "manager" to the other entry + try: + inst.modify_s(USER1_DN, [(ldap.MOD_REPLACE, 'indirectReport', USER2_DN)]) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to add "indirectReport" to user1: error ' + e.message['desc']) + assert False + + # See if manager was added to the other entry, better not be + try: + entries = inst.search_s(USER2_DN, ldap.SCOPE_BASE, '(manager=*)') + if not entries: + log.fatal('test_linkedattrs: user2 missing "manager"') + assert False + except ldap.LDAPError, e: + log.fatal('test_linkedattrs: Search for user2 failed: ' + e.message['desc']) + assert False + + # Remove "indirectReport" should remove "manager" to the other entry + try: + inst.modify_s(USER1_DN, [(ldap.MOD_DELETE, 'indirectReport', None)]) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to delete directReport: error ' + e.message['desc']) + assert False + + # See if manager was removed + try: + entries = inst.search_s(USER2_DN, ldap.SCOPE_BASE, '(manager=*)') + if entries: + log.fatal('test_linkedattrs: user2 "manager" attribute not removed') + assert False + except ldap.LDAPError, e: + log.fatal('test_linkedattrs: Search for user1 failed: ' + e.message['desc']) + assert False + + ############################################################################ + # Test Fixup Task + ############################################################################ + + # Disable plugin and make some updates that would of triggered the plugin + inst.plugins.disable(name=PLUGIN_LINKED_ATTRS) + + try: + inst.modify_s(USER1_DN, [(ldap.MOD_REPLACE, 'indirectReport', USER2_DN)]) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to add "indirectReport" to user1: error ' + e.message['desc']) + assert False + + # The entry should not have a manager attribute + try: + entries = inst.search_s(USER2_DN, ldap.SCOPE_BASE, '(manager=*)') + if entries: + log.fatal('test_linkedattrs: user2 incorrectly has a "manager" attr') + assert False + except ldap.LDAPError, e: + log.fatal('test_linkedattrs: Search for user1 failed: ' + e.message['desc']) + assert False + + # Verify that the task does not work yet(not until we enable the plugin) + try: + inst.add_s(Entry(('cn=task-' + str(int(time.time())) + ',cn=fixup linked attributes,cn=tasks,cn=config', { + 'objectclass': 'top extensibleObject'.split(), + 'basedn': DEFAULT_SUFFIX, + 'filter': '(objectclass=top)'}))) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to add task: error ' + e.message['desc']) + assert False + + time.sleep(3) # Wait for the task to do, or not do, its work + + # The entry should still not have a manager attribute + try: + entries = inst.search_s(USER2_DN, ldap.SCOPE_BASE, '(manager=*)') + if entries: + log.fatal('test_linkedattrs: user2 incorrectly has a "manager" attr') + assert False + except ldap.LDAPError, e: + log.fatal('test_linkedattrs: Search for user2 failed: ' + e.message['desc']) + assert False + + # Enable the plugin and rerun the task entry + inst.plugins.enable(name=PLUGIN_LINKED_ATTRS) + + # Add the task again + try: + inst.add_s(Entry(('cn=task-' + str(int(time.time())) + ',cn=fixup linked attributes,cn=tasks,cn=config', { + 'objectclass': 'top extensibleObject'.split(), + 'basedn': DEFAULT_SUFFIX, + 'filter': 'objectclass=top'}))) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to add task: error ' + e.message['desc']) + assert False + + time.sleep(3) # Wait for the task to do its work + + # Check if user2 now has a manager attribute now + try: + entries = inst.search_s(USER2_DN, ldap.SCOPE_BASE, '(manager=*)') + if not entries: + log.fatal('test_linkedattrs: task failed: user2 missing "manager" attr') + assert False + except ldap.LDAPError, e: + log.fatal('test_linkedattrs: Search for user1 failed: ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin dependency + ############################################################################ + + test_dependency(inst, PLUGIN_LINKED_ATTRS) + + ############################################################################ + # Cleanup + ############################################################################ + + try: + inst.delete_s(USER1_DN) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to delete test entry1: ' + e.message['desc']) + assert False + + try: + inst.delete_s(USER2_DN) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to delete test entry2: ' + e.message['desc']) + assert False + + try: + inst.delete_s(CONFIG_DN) + except ldap.LDAPError, e: + log.error('test_linkedattrs: Failed to delete plugin config entry: ' + e.message['desc']) + assert False + + ############################################################################ + # Test passed + ############################################################################ + + log.info('test_linkedattrs: PASS\n') + return + + +################################################################################ +# +# Test MemberOf Plugin (5) +# +################################################################################ +def test_memberof(inst, args=None): + # stop the plugin, and start it + inst.plugins.disable(name=PLUGIN_MEMBER_OF) + inst.plugins.enable(name=PLUGIN_MEMBER_OF) + + if args == "restart": + return + + PLUGIN_DN = 'cn=' + PLUGIN_MEMBER_OF + ',cn=plugins,cn=config' + + log.info('Testing ' + PLUGIN_MEMBER_OF + '...') + + ############################################################################ + # Configure plugin + ############################################################################ + + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, 'memberofgroupattr', 'member')]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to update config(member): error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # Add our test entries + try: + inst.add_s(Entry((USER1_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user1' + }))) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to add user1: error ' + e.message['desc']) + assert False + + try: + inst.add_s(Entry((GROUP_DN, { + 'objectclass': 'top groupOfNames groupOfUniqueNames extensibleObject'.split(), + 'cn': 'group', + 'member': USER1_DN + }))) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to add group: error ' + e.message['desc']) + assert False + + # Check if the user now has a "memberOf" attribute + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') + if not entries: + log.fatal('test_memberof: user1 missing memberOf') + assert False + except ldap.LDAPError, e: + log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) + assert False + + # Remove "member" should remove "memberOf" from the entry + try: + inst.modify_s(GROUP_DN, [(ldap.MOD_DELETE, 'member', None)]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to delete member: error ' + e.message['desc']) + assert False + + # Check that "memberOf" was removed + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') + if entries: + log.fatal('test_memberof: user1 incorrect has memberOf attr') + assert False + except ldap.LDAPError, e: + log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) + assert False + + ############################################################################ + # Change the config + ############################################################################ + + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, 'memberofgroupattr', 'uniquemember')]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to update config(uniquemember): error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + try: + inst.modify_s(GROUP_DN, [(ldap.MOD_REPLACE, 'uniquemember', USER1_DN)]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to add uniquemember: error ' + e.message['desc']) + assert False + + # Check if the user now has a "memberOf" attribute + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') + if not entries: + log.fatal('test_memberof: user1 missing memberOf') + assert False + except ldap.LDAPError, e: + log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) + assert False + + # Remove "uniquemember" should remove "memberOf" from the entry + try: + inst.modify_s(GROUP_DN, [(ldap.MOD_DELETE, 'uniquemember', None)]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to delete member: error ' + e.message['desc']) + assert False + + # Check that "memberOf" was removed + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') + if entries: + log.fatal('test_memberof: user1 incorrect has memberOf attr') + assert False + except ldap.LDAPError, e: + log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) + assert False + + ############################################################################ + # Test Fixup Task + ############################################################################ + + inst.plugins.disable(name=PLUGIN_MEMBER_OF) + + # Add uniquemember, should not update USER1 + try: + inst.modify_s(GROUP_DN, [(ldap.MOD_REPLACE, 'uniquemember', USER1_DN)]) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to add uniquemember: error ' + e.message['desc']) + assert False + + # Check for "memberOf" + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') + if entries: + log.fatal('test_memberof: user1 incorrect has memberOf attr') + assert False + except ldap.LDAPError, e: + log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) + assert False + + # Run fixup task while plugin disabled - should not add "memberOf + # Verify that the task does not work yet(not until we enable the plugin) + try: + inst.add_s(Entry(('cn=task-' + str(int(time.time())) + ',' + DN_MBO_TASK, { + 'objectclass': 'top extensibleObject'.split(), + 'basedn': DEFAULT_SUFFIX, + 'filter': 'objectclass=top'}))) + except ldap.NO_SUCH_OBJECT: + pass + except ldap.LDAPError, e: + log.error('test_memberof: Failed to add task: error ' + e.message['desc']) + assert False + + time.sleep(3) # Wait for the task to do, or not do, its work + + # Check for "memberOf" + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') + if entries: + log.fatal('test_memberof: user1 incorrectly has memberOf attr') + assert False + except ldap.LDAPError, e: + log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) + assert False + + # Enable the plugin, and run the task + inst.plugins.enable(name=PLUGIN_MEMBER_OF) + + try: + inst.add_s(Entry(('cn=task-' + str(int(time.time())) + ',' + DN_MBO_TASK, { + 'objectclass': 'top extensibleObject'.split(), + 'basedn': DEFAULT_SUFFIX, + 'filter': 'objectclass=top'}))) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to add task: error ' + e.message['desc']) + assert False + + time.sleep(3) # Wait for the task to do its work + + # Check for "memberOf" + try: + entries = inst.search_s(USER1_DN, ldap.SCOPE_BASE, '(memberOf=*)') + if not entries: + log.fatal('test_memberof: user1 missing memberOf attr') + assert False + except ldap.LDAPError, e: + log.fatal('test_memberof: Search for user1 failed: ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin dependency + ############################################################################ + + test_dependency(inst, PLUGIN_MEMBER_OF) + + ############################################################################ + # Cleanup + ############################################################################ + + try: + inst.delete_s(USER1_DN) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to delete test entry1: ' + e.message['desc']) + assert False + + try: + inst.delete_s(GROUP_DN) + except ldap.LDAPError, e: + log.error('test_memberof: Failed to delete test group: ' + e.message['desc']) + assert False + + ############################################################################ + # Test passed + ############################################################################ + + log.info('test_memberof: PASS\n') + + return + + +################################################################################ +# +# Test Managed Entry Plugin (6) +# +################################################################################ +def test_mep(inst, args=None): + # stop the plugin, and start it + inst.plugins.disable(name=PLUGIN_MANAGED_ENTRY) + inst.plugins.enable(name=PLUGIN_MANAGED_ENTRY) + + if args == "restart": + return + + USER_DN = 'uid=user1,ou=people,' + DEFAULT_SUFFIX + MEP_USER_DN = 'cn=user1,ou=groups,' + DEFAULT_SUFFIX + USER_DN2 = 'uid=user 1,ou=people,' + DEFAULT_SUFFIX + MEP_USER_DN2 = 'uid=user 1,ou=groups,' + DEFAULT_SUFFIX + CONFIG_DN = 'cn=config,cn=' + PLUGIN_MANAGED_ENTRY + ',cn=plugins,cn=config' + TEMPLATE_DN = 'cn=MEP Template,' + DEFAULT_SUFFIX + TEMPLATE_DN2 = 'cn=MEP Template2,' + DEFAULT_SUFFIX + + log.info('Testing ' + PLUGIN_MANAGED_ENTRY + '...') + + ############################################################################ + # Configure plugin + ############################################################################ + + # Add our org units + try: + inst.add_s(Entry((PEOPLE_OU, { + 'objectclass': 'top extensibleObject'.split(), + 'ou': 'people'}))) + except ldap.ALREADY_EXISTS: + pass + except ldap.LDAPError, e: + log.error('test_mep: Failed to add people org unit: error ' + e.message['desc']) + assert False + + try: + inst.add_s(Entry((GROUP_OU, { + 'objectclass': 'top extensibleObject'.split(), + 'ou': 'people'}))) + except ldap.ALREADY_EXISTS: + pass + except ldap.LDAPError, e: + log.error('test_mep: Failed to add people org unit: error ' + e.message['desc']) + assert False + + # Add the template entry + try: + inst.add_s(Entry((TEMPLATE_DN, { + 'objectclass': 'top mepTemplateEntry extensibleObject'.split(), + 'cn': 'MEP Template', + 'mepRDNAttr': 'cn', + 'mepStaticAttr': 'objectclass: posixGroup|objectclass: extensibleObject'.split('|'), + 'mepMappedAttr': 'cn: $cn|uid: $cn|gidNumber: $uidNumber'.split('|') + }))) + except ldap.LDAPError, e: + log.error('test_mep: Failed to add template entry: error ' + e.message['desc']) + assert False + + # log.info('geb.....') + # time.sleep(30) + + # Add the config entry + try: + inst.add_s(Entry((CONFIG_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'cn': 'config', + 'originScope': PEOPLE_OU, + 'originFilter': 'objectclass=posixAccount', + 'managedBase': GROUP_OU, + 'managedTemplate': TEMPLATE_DN + }))) + except ldap.LDAPError, e: + log.error('test_mep: Failed to add config entry: error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # Add an entry that meets the MEP scope + try: + inst.add_s(Entry((USER_DN, { + 'objectclass': 'top posixAccount extensibleObject'.split(), + 'uid': 'user1', + 'cn': 'user1', + 'uidNumber': '1', + 'gidNumber': '1', + 'homeDirectory': '/home/user1' + }))) + except ldap.LDAPError, e: + log.error('test_mep: Failed to user1: error ' + e.message['desc']) + assert False + + # Check if a managed group entry was created + try: + inst.search_s(MEP_USER_DN, ldap.SCOPE_BASE, '(objectclass=top)') + except ldap.LDAPError, e: + log.fatal('test_mep: Unable to find MEP entry: ' + e.message['desc']) + assert False + + ############################################################################ + # Change the config + ############################################################################ + + # Add a new template entry + try: + inst.add_s(Entry((TEMPLATE_DN2, { + 'objectclass': 'top mepTemplateEntry extensibleObject'.split(), + 'cn': 'MEP Template2', + 'mepRDNAttr': 'uid', + 'mepStaticAttr': 'objectclass: posixGroup|objectclass: extensibleObject'.split('|'), + 'mepMappedAttr': 'cn: $uid|uid: $cn|gidNumber: $gidNumber'.split('|') + }))) + except ldap.LDAPError, e: + log.error('test_mep: Failed to add template entry2: error ' + e.message['desc']) + assert False + + # Set the new template dn + try: + inst.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'managedTemplate', TEMPLATE_DN2)]) + except ldap.LDAPError, e: + log.error('test_mep: Failed to set mep plugin config: error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # Add an entry that meets the MEP scope + try: + inst.add_s(Entry((USER_DN2, { + 'objectclass': 'top posixAccount extensibleObject'.split(), + 'uid': 'user 1', + 'cn': 'user 1', + 'uidNumber': '1', + 'gidNumber': '1', + 'homeDirectory': '/home/user2' + }))) + except ldap.LDAPError, e: + log.error('test_mep: Failed to user2: error ' + e.message['desc']) + assert False + + # Check if a managed group entry was created + try: + inst.search_s(MEP_USER_DN2, ldap.SCOPE_BASE, '(objectclass=top)') + except ldap.LDAPError, e: + log.fatal('test_mep: Unable to find MEP entry2: ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin dependency + ############################################################################ + + test_dependency(inst, PLUGIN_MANAGED_ENTRY) + + ############################################################################ + # Cleanup + ############################################################################ + + try: + inst.delete_s(USER_DN) + except ldap.LDAPError, e: + log.error('test_mep: Failed to delete test user1: ' + e.message['desc']) + assert False + + try: + inst.delete_s(USER_DN2) + except ldap.LDAPError, e: + log.error('test_mep: Failed to delete test user 2: ' + e.message['desc']) + assert False + + try: + inst.delete_s(TEMPLATE_DN) + except ldap.LDAPError, e: + log.error('test_mep: Failed to delete template1: ' + e.message['desc']) + assert False + + inst.plugins.disable(name=PLUGIN_MANAGED_ENTRY) + + try: + inst.delete_s(TEMPLATE_DN2) + except ldap.LDAPError, e: + log.error('test_mep: Failed to delete template2: ' + e.message['desc']) + assert False + + try: + inst.delete_s(CONFIG_DN) + except ldap.LDAPError, e: + log.error('test_mep: Failed to delete config: ' + e.message['desc']) + assert False + + ############################################################################ + # Test passed + ############################################################################ + + log.info('test_mep: PASS\n') + return + + +################################################################################ +# +# Test Passthru Plugin (7) +# +################################################################################ +def test_passthru(inst, args=None): + # Passthru is a bit picky about the state of the entry - we can't just restart it + if args == "restart": + return + + # stop the plugin + inst.plugins.disable(name=PLUGIN_PASSTHRU) + + PLUGIN_DN = 'cn=' + PLUGIN_PASSTHRU + ',cn=plugins,cn=config' + PASSTHRU_DN = 'uid=admin,dc=pass,dc=thru' + PASSTHRU_DN2 = 'uid=admin2,dc=pass2,dc=thru' + PASS_SUFFIX1 = 'dc=pass,dc=thru' + PASS_SUFFIX2 = 'dc=pass2,dc=thru' + PASS_BE2 = 'PASS2' + + log.info('Testing ' + PLUGIN_PASSTHRU + '...') + + ############################################################################ + # Add a new "remote" instance, and a user for auth + ############################################################################ + + # Create second instance + passthru_inst = DirSrv(verbose=False) + + #if installation1_prefix: + # args_instance[SER_DEPLOYED_DIR] = installation1_prefix + + # Args for the master1 instance + """ + args_instance[SER_HOST] = '127.0.0.1' + args_instance[SER_PORT] = '33333' + args_instance[SER_SERVERID_PROP] = 'passthru' + """ + args_instance[SER_HOST] = 'localhost.localdomain' + args_instance[SER_PORT] = 33333 + args_instance[SER_SERVERID_PROP] = 'passthru' + + args_instance[SER_CREATION_SUFFIX] = PASS_SUFFIX1 + args_passthru_inst = args_instance.copy() + passthru_inst.allocate(args_passthru_inst) + passthru_inst.create() + passthru_inst.open() + + # Create a second backend + passthru_inst.backend.create(PASS_SUFFIX2, {BACKEND_NAME: PASS_BE2}) + passthru_inst.mappingtree.create(PASS_SUFFIX2, bename=PASS_BE2) + + # Create the top of the tree + try: + passthru_inst.add_s(Entry((PASS_SUFFIX2, { + 'objectclass': 'top domain'.split(), + 'dc': 'pass2'}))) + except ldap.ALREADY_EXISTS: + pass + except ldap.LDAPError, e: + log.error('test_passthru: Failed to create suffix entry: error ' + e.message['desc']) + passthru_inst.delete() + assert False + + # Add user to suffix1 + try: + passthru_inst.add_s(Entry((PASSTHRU_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'admin', + 'userpassword': 'password' + }))) + except ldap.LDAPError, e: + log.error('test_passthru: Failed to admin1: error ' + e.message['desc']) + passthru_inst.delete() + assert False + + # Add user to suffix 2 + try: + passthru_inst.add_s(Entry((PASSTHRU_DN2, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'admin2', + 'userpassword': 'password' + }))) + except ldap.LDAPError, e: + log.error('test_passthru: Failed to admin2 : error ' + e.message['desc']) + passthru_inst.delete() + assert False + + ############################################################################ + # Configure and start plugin + ############################################################################ + + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, 'nsslapd-pluginenabled', 'on'), + (ldap.MOD_REPLACE, 'nsslapd-pluginarg0', 'ldap://127.0.0.1:33333/dc=pass,dc=thru')]) + except ldap.LDAPError, e: + log.error('test_passthru: Failed to set mep plugin config: error ' + e.message['desc']) + passthru_inst.delete() + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # login as user + try: + inst.simple_bind_s(PASSTHRU_DN, "password") + except ldap.LDAPError, e: + log.error('test_passthru: pass through bind failed: ' + e.message['desc']) + passthru_inst.delete() + assert False + + ############################################################################ + # Change the config + ############################################################################ + + # login as root DN + try: + inst.simple_bind_s(DN_DM, PASSWORD) + except ldap.LDAPError, e: + log.error('test_passthru: pass through bind failed: ' + e.message['desc']) + passthru_inst.delete() + assert False + + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, 'nsslapd-pluginarg0', 'ldap://127.0.0.1:33333/dc=pass2,dc=thru')]) + except ldap.LDAPError, e: + log.error('test_passthru: Failed to set mep plugin config: error ' + e.message['desc']) + passthru_inst.delete() + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # login as user + try: + inst.simple_bind_s(PASSTHRU_DN2, "password") + except ldap.LDAPError, e: + log.error('test_passthru: pass through bind failed: ' + e.message['desc']) + passthru_inst.delete() + assert False + + # login as root DN + try: + inst.simple_bind_s(DN_DM, PASSWORD) + except ldap.LDAPError, e: + log.error('test_passthru: pass through bind failed: ' + e.message['desc']) + passthru_inst.delete() + assert False + + ############################################################################ + # Test plugin dependency + ############################################################################ + + test_dependency(inst, PLUGIN_PASSTHRU) + + ############################################################################ + # Cleanup + ############################################################################ + + # remove the passthru instance + passthru_inst.delete() + + ############################################################################ + # Test passed + ############################################################################ + + log.info('test_passthru: PASS\n') + + return + + +################################################################################ +# +# Test Referential Integrity Plugin (8) +# +################################################################################ +def test_referint(inst, args=None): + # stop the plugin, and start it + inst.plugins.disable(name=PLUGIN_REFER_INTEGRITY) + inst.plugins.enable(name=PLUGIN_REFER_INTEGRITY) + + if args == "restart": + return + + log.info('Testing ' + PLUGIN_REFER_INTEGRITY + '...') + PLUGIN_DN = 'cn=' + PLUGIN_REFER_INTEGRITY + ',cn=plugins,cn=config' + + ############################################################################ + # Configure plugin + ############################################################################ + + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, 'referint-membership-attr', 'member')]) + except ldap.LDAPError, e: + log.error('test_referint: Failed to configure RI plugin: error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # Add some users and a group + try: + inst.add_s(Entry((USER1_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user1' + }))) + except ldap.LDAPError, e: + log.error('test_referint: Failed to add user1: error ' + e.message['desc']) + assert False + + try: + inst.add_s(Entry((USER2_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user2' + }))) + except ldap.LDAPError, e: + log.error('test_referint: Failed to add user2: error ' + e.message['desc']) + assert False + + try: + inst.add_s(Entry((GROUP_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'cn': 'group', + 'member': USER1_DN, + 'uniquemember': USER2_DN + }))) + except ldap.LDAPError, e: + log.error('test_referint: Failed to add group: error ' + e.message['desc']) + assert False + + # Delete a user + try: + inst.delete_s(USER1_DN) + except ldap.LDAPError, e: + log.error('test_referint: Failed to delete user1: ' + e.message['desc']) + assert False + + # Check for integrity + try: + entry = inst.search_s(GROUP_DN, ldap.SCOPE_BASE, '(member=' + USER1_DN + ')') + if entry: + log.error('test_referint: user1 was not removed from group') + assert False + except ldap.LDAPError, e: + log.fatal('test_referint: Unable to search group: ' + e.message['desc']) + assert False + + ############################################################################ + # Change the config + ############################################################################ + + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, 'referint-membership-attr', 'uniquemember')]) + except ldap.LDAPError, e: + log.error('test_referint: Failed to configure RI plugin: error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # Delete a user + try: + inst.delete_s(USER2_DN) + except ldap.LDAPError, e: + log.error('test_referint: Failed to delete user1: ' + e.message['desc']) + assert False + + # Check for integrity + try: + entry = inst.search_s(GROUP_DN, ldap.SCOPE_BASE, '(uniquemember=' + USER2_DN + ')') + if entry: + log.error('test_referint: user2 was not removed from group') + assert False + except ldap.LDAPError, e: + log.fatal('test_referint: Unable to search group: ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin dependency + ############################################################################ + + test_dependency(inst, PLUGIN_REFER_INTEGRITY) + + ############################################################################ + # Cleanup + ############################################################################ + + try: + inst.delete_s(GROUP_DN) + except ldap.LDAPError, e: + log.error('test_referint: Failed to delete user1: ' + e.message['desc']) + assert False + + ############################################################################ + # Test passed + ############################################################################ + + log.info('test_referint: PASS\n') + + return + + +################################################################################ +# +# Test Retro Changelog Plugin (9) +# +################################################################################ +def test_retrocl(inst, args=None): + # stop the plugin, and start it + inst.plugins.disable(name=PLUGIN_RETRO_CHANGELOG) + inst.plugins.enable(name=PLUGIN_RETRO_CHANGELOG) + + if args == "restart": + return + + log.info('Testing ' + PLUGIN_RETRO_CHANGELOG + '...') + + ############################################################################ + # Configure plugin + ############################################################################ + + # Gather the current change count (it's not 1 once we start the stabilty tests) + try: + entry = inst.search_s(RETROCL_SUFFIX, ldap.SCOPE_SUBTREE, '(changenumber=*)') + except ldap.LDAPError, e: + log.error('test_retrocl: Failed to get the count: error ' + e.message['desc']) + assert False + + entry_count = len(entry) + + ############################################################################ + # Test plugin + ############################################################################ + + # Add a user + try: + inst.add_s(Entry((USER1_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user1' + }))) + except ldap.LDAPError, e: + log.error('test_retrocl: Failed to add user1: error ' + e.message['desc']) + assert False + + # Check we logged this in the retro cl + try: + entry = inst.search_s(RETROCL_SUFFIX, ldap.SCOPE_SUBTREE, '(changenumber=*)') + if not entry or len(entry) == entry_count: + log.error('test_retrocl: changelog not updated') + assert False + except ldap.LDAPError, e: + log.fatal('test_retrocl: Unable to search group: ' + e.message['desc']) + assert False + + entry_count += 1 + + ############################################################################ + # Change the config - disable plugin + ############################################################################ + + inst.plugins.disable(name=PLUGIN_RETRO_CHANGELOG) + + ############################################################################ + # Test plugin + ############################################################################ + + try: + inst.delete_s(USER1_DN) + except ldap.LDAPError, e: + log.error('test_retrocl: Failed to delete user1: ' + e.message['desc']) + assert False + + # Check we didn't logged this in the retro cl + try: + entry = inst.search_s(RETROCL_SUFFIX, ldap.SCOPE_SUBTREE, '(changenumber=*)') + if len(entry) != entry_count: + log.error('test_retrocl: changelog incorrectly updated - change count: ' + + str(len(entry)) + ' - expected 1') + assert False + except ldap.LDAPError, e: + log.fatal('test_retrocl: Unable to search retro changelog: ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin dependency + ############################################################################ + + inst.plugins.enable(name=PLUGIN_RETRO_CHANGELOG) + test_dependency(inst, PLUGIN_RETRO_CHANGELOG) + + ############################################################################ + # Cleanup + ############################################################################ + + # None + + ############################################################################ + # Test passed + ############################################################################ + + log.info('test_retrocl: PASS\n') + + return + + +################################################################################ +# +# Test Root DN Access Control Plugin (10) +# +################################################################################ +def test_rootdn(inst, args=None): + # stop the plugin, and start it + inst.plugins.disable(name=PLUGIN_ROOTDN_ACCESS) + inst.plugins.enable(name=PLUGIN_ROOTDN_ACCESS) + + if args == "restart": + return + + PLUGIN_DN = 'cn=' + PLUGIN_ROOTDN_ACCESS + ',cn=plugins,cn=config' + + ############################################################################ + # Configure plugin + ############################################################################ + + # Add an user and aci to open up cn=config + try: + inst.add_s(Entry((USER1_DN, { + 'objectclass': 'top extensibleObject'.split(), + 'uid': 'user1', + 'userpassword': 'password' + }))) + except ldap.LDAPError, e: + log.error('test_retrocl: Failed to add user1: error ' + e.message['desc']) + assert False + + # Set an aci so we can modify the plugin after ew deny the root dn + ACI = '(target ="ldap:///cn=config")(targetattr = "*")(version 3.0;acl "all access";allow (all)(userdn="ldap:///anyone");)' + try: + inst.modify_s(DN_CONFIG, [(ldap.MOD_ADD, 'aci', ACI)]) + except ldap.LDAPError, e: + log.error('test_rootdn: Failed to add aci to config: error ' + e.message['desc']) + assert False + + # Set allowed IP to an unknown host - blocks root dn + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, 'rootdn-allow-ip', '10.10.10.10')]) + except ldap.LDAPError, e: + log.error('test_rootdn: Failed to set rootDN plugin config: error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # Bind as Root DN + failed = False + try: + inst.simple_bind_s(DN_DM, PASSWORD) + except ldap.LDAPError, e: + failed = True + + if not failed: + log.error('test_rootdn: Root DN was incorrectly able to bind') + assert False + + ############################################################################ + # Change the config + ############################################################################ + + try: + inst.simple_bind_s(USER1_DN, 'password') + except ldap.LDAPError, e: + log.error('test_rootdn: failed to bind as user1') + assert False + + # Remove the restriction + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_DELETE, 'rootdn-allow-ip', None)]) + except ldap.LDAPError, e: + log.error('test_rootdn: Failed to set rootDN plugin config: error ' + e.message['desc']) + assert False + + ############################################################################ + # Test plugin + ############################################################################ + + # Bind as Root DN + failed = False + try: + inst.simple_bind_s(DN_DM, PASSWORD) + except ldap.LDAPError, e: + failed = True + + if failed: + log.error('test_rootdn: Root DN was not able to bind') + assert False + + ############################################################################ + # Test plugin dependency + ############################################################################ + + test_dependency(inst, PLUGIN_ROOTDN_ACCESS) + + ############################################################################ + # Cleanup - remove ACI from cn=config and test user + ############################################################################ + + try: + inst.modify_s(DN_CONFIG, [(ldap.MOD_DELETE, 'aci', ACI)]) + except ldap.LDAPError, e: + log.error('test_rootdn: Failed to add aci to config: error ' + e.message['desc']) + assert False + + try: + inst.delete_s(USER1_DN) + except ldap.LDAPError, e: + log.error('test_rootdn: Failed to delete user1: ' + e.message['desc']) + assert False + + ############################################################################ + # Test passed + ############################################################################ + + log.info('test_rootdn: PASS\n') + + return + + +# Array of test functions +func_tests = [test_acctpolicy, test_attruniq, test_automember, test_dna, + test_linkedattrs, test_memberof, test_mep, test_passthru, + test_referint, test_retrocl, test_rootdn] + + +def test_all_plugins(inst, args=None): + for func in func_tests: + func(inst, args) + + return + diff --git a/dirsrvtests/suites/dynamic-plugins/stress_tests.py b/dirsrvtests/suites/dynamic-plugins/stress_tests.py new file mode 100644 index 0000000..a1f666d --- /dev/null +++ b/dirsrvtests/suites/dynamic-plugins/stress_tests.py @@ -0,0 +1,133 @@ +''' +Created on Dec 16, 2014 + +@author: mreynolds +''' +import os +import sys +import time +import ldap +import time +import logging +import socket +import pytest +import threading +from lib389 import DirSrv, Entry, tools, tasks +from lib389.tools import DirSrvTools +from lib389._constants import * +from lib389.properties import * +from constants import * + +log = logging.getLogger(__name__) + +NUM_USERS = 250 + + +def openConnection(inst): + # Open a new connection to our LDAP server + server = DirSrv(verbose=False) + args_instance[SER_HOST] = HOST_STANDALONE + args_instance[SER_PORT] = PORT_STANDALONE + args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE + args_standalone = args_instance.copy() + server.allocate(args_standalone) + server.open() + + return server + + +# Configure Referential Integrity Plugin for stress test +def configureRI(inst): + inst.plugins.enable(name=PLUGIN_REFER_INTEGRITY) + PLUGIN_DN = 'cn=' + PLUGIN_REFER_INTEGRITY + ',cn=plugins,cn=config' + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, 'referint-membership-attr', 'uniquemember')]) + except ldap.LDAPError, e: + log.error('configureRI: Failed to configure RI plugin: error ' + e.message['desc']) + assert False + + +# Configure MemberOf Plugin for stress test +def configureMO(inst): + inst.plugins.enable(name=PLUGIN_MEMBER_OF) + PLUGIN_DN = 'cn=' + PLUGIN_MEMBER_OF + ',cn=plugins,cn=config' + try: + inst.modify_s(PLUGIN_DN, [(ldap.MOD_REPLACE, 'memberofgroupattr', 'uniquemember')]) + except ldap.LDAPError, e: + log.error('configureMO: Failed to update config(uniquemember): error ' + e.message['desc']) + assert False + + +class DelUsers(threading.Thread): + def __init__(self, inst, rdnval): + threading.Thread.__init__(self) + self.daemon = True + self.inst = inst + self.rdnval = rdnval + + def run(self): + conn = openConnection(self.inst) + idx = 0 + log.info('DelUsers - Deleting ' + str(NUM_USERS) + ' entries (' + self.rdnval + ')...') + while idx < NUM_USERS: + USER_DN = 'uid=' + self.rdnval + str(idx) + ',' + DEFAULT_SUFFIX + try: + conn.delete_s(USER_DN) + except ldap.LDAPError, e: + log.error('DeleteUsers: failed to delete (' + USER_DN + ') error: ' + e.message['desc']) + assert False + + idx += 1 + + conn.close() + log.info('DelUsers - Finished deleting ' + str(NUM_USERS) + ' entries (' + self.rdnval + ').') + + +class AddUsers(threading.Thread): + def __init__(self, inst, rdnval, addToGroup): + threading.Thread.__init__(self) + self.daemon = True + self.inst = inst + self.addToGroup = addToGroup + self.rdnval = rdnval + + def run(self): + # Start adding users + conn = openConnection(self.inst) + idx = 0 + + if self.addToGroup: + GROUP_DN = 'cn=stress-group,' + DEFAULT_SUFFIX + try: + conn.add_s(Entry((GROUP_DN, + {'objectclass': 'top groupOfNames groupOfUniqueNames extensibleObject'.split(), + 'uid': 'user' + str(idx)}))) + except ldap.ALREADY_EXISTS: + pass + except ldap.LDAPError, e: + log.error('AddUsers: failed to add group (' + USER_DN + ') error: ' + e.message['desc']) + assert False + + log.info('AddUsers - Adding ' + str(NUM_USERS) + ' entries (' + self.rdnval + ')...') + + while idx < NUM_USERS: + USER_DN = 'uid=' + self.rdnval + str(idx) + ',' + DEFAULT_SUFFIX + try: + conn.add_s(Entry((USER_DN, {'objectclass': 'top extensibleObject'.split(), + 'uid': 'user' + str(idx)}))) + except ldap.LDAPError, e: + log.error('AddUsers: failed to add (' + USER_DN + ') error: ' + e.message['desc']) + assert False + + if self.addToGroup: + # Add the user to the group + try: + conn.modify_s(GROUP_DN, [(ldap.MOD_ADD, 'uniquemember', USER_DN)]) + except ldap.LDAPError, e: + log.error('AddUsers: Failed to add user' + USER_DN + ' to group: error ' + e.message['desc']) + assert False + + idx += 1 + + conn.close() + log.info('AddUsers - Finished adding ' + str(NUM_USERS) + ' entries (' + self.rdnval + ').') diff --git a/dirsrvtests/suites/dynamic-plugins/test_dynamic_plugins.py b/dirsrvtests/suites/dynamic-plugins/test_dynamic_plugins.py new file mode 100644 index 0000000..3677fd5 --- /dev/null +++ b/dirsrvtests/suites/dynamic-plugins/test_dynamic_plugins.py @@ -0,0 +1,315 @@ +''' +Created on Dec 09, 2014 + +@author: mreynolds +''' +import os +import sys +import time +import ldap +import ldap.sasl +import logging +import socket +import pytest +import plugin_tests +import stress_tests +from lib389 import DirSrv, Entry, tools, tasks +from lib389.tools import DirSrvTools +from lib389._constants import * +from lib389.properties import * +from lib389.tasks import * +from constants import * + +log = logging.getLogger(__name__) + +installation_prefix = None + + +class TopologyStandalone(object): + def __init__(self, standalone): + standalone.open() + self.standalone = standalone + + +@pytest.fixture(scope="module") +def topology(request): + ''' + This fixture is used to standalone topology for the 'module'. + At the beginning, It may exists a standalone instance. + It may also exists a backup for the standalone instance. + + Principle: + If standalone instance exists: + restart it + If backup of standalone exists: + create/rebind to standalone + + restore standalone instance from backup + else: + Cleanup everything + remove instance + remove backup + Create instance + Create backup + ''' + global installation_prefix + + if installation_prefix: + args_instance[SER_DEPLOYED_DIR] = installation_prefix + + standalone = DirSrv(verbose=False) + + # Args for the standalone instance + args_instance[SER_HOST] = HOST_STANDALONE + args_instance[SER_PORT] = PORT_STANDALONE + args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE + args_standalone = args_instance.copy() + standalone.allocate(args_standalone) + + # Get the status of the backups + backup_standalone = standalone.checkBackupFS() + + # Get the status of the instance and restart it if it exists + instance_standalone = standalone.exists() + if instance_standalone: + # assuming the instance is already stopped, just wait 5 sec max + standalone.stop(timeout=5) + standalone.start(timeout=10) + + if backup_standalone: + # The backup exist, assuming it is correct + # we just re-init the instance with it + if not instance_standalone: + standalone.create() + # Used to retrieve configuration information (dbdir, confdir...) + standalone.open() + + # restore standalone instance from backup + standalone.stop(timeout=10) + standalone.restoreFS(backup_standalone) + standalone.start(timeout=10) + + else: + # We should be here only in two conditions + # - This is the first time a test involve standalone instance + # - Something weird happened (instance/backup destroyed) + # so we discard everything and recreate all + + # Remove the backup. So even if we have a specific backup file + # (e.g backup_standalone) we clear backup that an instance may have created + if backup_standalone: + standalone.clearBackupFS() + + # Remove the instance + if instance_standalone: + standalone.delete() + + # Create the instance + standalone.create() + + # Used to retrieve configuration information (dbdir, confdir...) + standalone.open() + + # Time to create the backups + standalone.stop(timeout=10) + standalone.backupfile = standalone.backupFS() + standalone.start(timeout=10) + + # + # Here we have standalone instance up and running + # Either coming from a backup recovery + # or from a fresh (re)init + # Time to return the topology + return TopologyStandalone(standalone) + + +def test_dynamic_plugins(topology): + """ + Test Dynamic Plugins - exercise each plugin and its main features, while + changing the configuration without restarting the server. + + Need to test: functionality, stability, and stress. + + Functionality - Make sure that as configuration changes are made they take + effect immediately. Cross plugin interaction (e.g. automember/memberOf) + needs to tested, as well as plugin tasks. Need to test plugin + config validation(dependencies, etc). + + Memory Corruption - Restart the plugins many times, and in different orders and test + functionality, and stability. This will excerise the internal + plugin linked lists, dse callabcks, and task handlers. + + Stress - Put the server under some type of load that is using a particular + plugin for each operation, and then make changes to that plugin. + The new changes should take effect, and the server should not crash. + + """ + + ############################################################################ + # Test plugin functionality + ############################################################################ + + # First enable dynamic plugins + try: + topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-dynamic-plugins', 'on')]) + except ldap.LDAPError, e: + ldap.error('Failed to enable dynamic plugin!' + e.message['desc']) + assert False + + log.info('#####################################################') + log.info('Testing Dynamic Plugins Functionality...') + log.info('#####################################################\n') + + plugin_tests.test_all_plugins(topology.standalone) + + log.info('#####################################################') + log.info('Successfully Tested Dynamic Plugins Functionality.') + log.info('#####################################################\n') + + ############################################################################ + # Test the stability by exercising the internal lists, callabcks, and task handlers + ############################################################################ + + log.info('#####################################################') + log.info('Testing Dynamic Plugins for Memory Corruption...') + log.info('#####################################################\n') + prev_plugin_test = None + prev_prev_plugin_test = None + for plugin_test in plugin_tests.func_tests: + # + # Restart the plugin several times (and prev plugins) - work that linked list + # + plugin_test(topology.standalone, "restart") + + if prev_prev_plugin_test: + prev_prev_plugin_test(topology.standalone, "restart") + + plugin_test(topology.standalone, "restart") + + if prev_plugin_test: + prev_plugin_test(topology.standalone, "restart") + + plugin_test(topology.standalone, "restart") + + # Now run the functional test + plugin_test(topology.standalone) + + # Set the previous tests + if prev_plugin_test: + prev_prev_plugin_test = prev_plugin_test + prev_plugin_test = plugin_test + + log.info('#####################################################') + log.info('Successfully Tested Dynamic Plugins for Memory Corruption.') + log.info('#####################################################\n') + + ############################################################################ + # Stress two plugins while restarting it, and while restarting other plugins. + # The goal is to not crash, and have the plugins work after stressing it. + ############################################################################ + + log.info('#####################################################') + log.info('Stressing Dynamic Plugins...') + log.info('#####################################################\n') + + # Configure the plugins + stress_tests.configureMO(topology.standalone) + stress_tests.configureRI(topology.standalone) + + # Launch three new threads to add a bunch of users + add_users = stress_tests.AddUsers(topology.standalone, 'user', True) + add_users.start() + add_users2 = stress_tests.AddUsers(topology.standalone, 'entry', True) + add_users2.start() + add_users3 = stress_tests.AddUsers(topology.standalone, 'person', True) + add_users3.start() + time.sleep(1) + + # While we are adding users restart the MO plugin + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + time.sleep(3) + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + time.sleep(1) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + + # Restart idle plugin + topology.standalone.plugins.disable(name=PLUGIN_LINKED_ATTRS) + topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS) + + # Wait for the 'adding' threads to complete + add_users.join() + add_users2.join() + add_users3.join() + + # Now launch three threads to delete the users, and restart both the MO and RI plugins + del_users = stress_tests.DelUsers(topology.standalone, 'user') + del_users.start() + del_users2 = stress_tests.DelUsers(topology.standalone, 'entry') + del_users2.start() + del_users3 = stress_tests.DelUsers(topology.standalone, 'person') + del_users3.start() + time.sleep(1) + + # Restart the both the MO and RI plugins during these deletes + + topology.standalone.plugins.disable(name=PLUGIN_REFER_INTEGRITY) + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + topology.standalone.plugins.enable(name=PLUGIN_REFER_INTEGRITY) + time.sleep(3) + topology.standalone.plugins.disable(name=PLUGIN_REFER_INTEGRITY) + time.sleep(1) + topology.standalone.plugins.disable(name=PLUGIN_MEMBER_OF) + time.sleep(1) + topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) + time.sleep(1) + topology.standalone.plugins.enable(name=PLUGIN_REFER_INTEGRITY) + + # Restart idle plugin + topology.standalone.plugins.disable(name=PLUGIN_LINKED_ATTRS) + topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS) + + # Wait for the 'deleting' threads to complete + del_users.join() + del_users2.join() + del_users3.join() + + # Now make sure both the MO and RI plugins still work + plugin_tests.func_tests[8](topology.standalone) # RI plugin + plugin_tests.func_tests[5](topology.standalone) # MO plugin + + log.info('#####################################################') + log.info('Successfully Stressed Dynamic Plugins.') + log.info('#####################################################\n') + + ############################################################################ + # We made it to the end! + ############################################################################ + + log.info('#####################################################') + log.info('#####################################################') + log.info("Dynamic Plugins Testsuite: Completed Successfully!") + log.info('#####################################################') + log.info('#####################################################') + +def test_dynamic_plugins_final(topology): + topology.standalone.stop(timeout=10) + + +def run_isolated(): + ''' + run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..) + To run isolated without py.test, you need to + - edit this file and comment '@pytest.fixture' line before 'topology' function. + - set the installation prefix + - run this program + ''' + global installation_prefix + installation_prefix = None + + topo = topology(True) + test_dynamic_plugins(topo) + +if __name__ == '__main__': + run_isolated() -- 1.9.3