diff --git a/integration/stick/imap.py b/integration/stick/imap.py index 85a23e4..a5fc7ba 100644 --- a/integration/stick/imap.py +++ b/integration/stick/imap.py @@ -1,16 +1,16 @@ -import traceback +import sys from pykolab.imap import IMAP def purge_imap(): """ Delete all IMAP mailboxes """ imap = IMAP() imap.connect() for folder in imap.lm(): try: imap.dm(folder) - except: - traceback.print_exc() + except Exception, e: + print >> sys.stderr, "WARNING: Delete", folder, "failed:", e diff --git a/integration/stick/integrationtest.py b/integration/stick/integrationtest.py index f9fcc85..1460bf2 100644 --- a/integration/stick/integrationtest.py +++ b/integration/stick/integrationtest.py @@ -1,163 +1,161 @@ import unittest import pykolab import datetime -import time from . import wipeall from . import synchronize from . import get_user from . import add_user from . import get_resource from . import add_resource from . import get_shared_folder from . import add_shared_folder from pykolab import wap_client conf = pykolab.getConf() class KolabIntegrationTest(unittest.TestCase): """ Base class providing utility functions for running integration tests """ wiped = False dosync = False initialized = False cleanafter = conf.get('testing', 'cleanafter') == 'true' develmode = conf.get('testing', 'develmode') == 'true' verbose = conf.get('testing', 'verbose') == 'true' or conf.cli_keywords.verbose @classmethod def __setUp(self, *args, **kw): """ Trigger setUpClass() once """ if not self.initialized: self.setUpClass() @classmethod def setUpClass(self, *args, **kw): """ Call this at the end of the derived setUpClass() method """ self.initialized = True if self.dosync: - time.sleep(1) self.log("Synchronize...") synchronize() self.dosync = False @classmethod def tearDownClass(self): if not self.develmode and self.cleanafter: self.log("Wipe data after") wipeall() if wap_client.conn and hasattr(wap_client, 'disconnect'): - wap_client.disconnect() + wap_client.disconnect(True) @classmethod def log(self, message): if self.verbose: print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:23] + " " + message @classmethod def require_user(self, givenname, sn, **kw): """ Create the given user and return its full properties """ create = not self.initialized and not self.develmode res = { 'givenname': givenname, 'sn': sn } res.update(kw) if not create: query = get_user(givenname, sn) self.log("User found: %r" % (query.get('mail','') if isinstance(query, dict) else query)) if len(query) > 0: res = query res['userpassword'] = 'Welcome2KolabSystems' else: create = True else: self._wipefirst() if create: res = add_user(givenname, sn, **kw) self.log("Added user: %r" % (res.get('mail',''))) self.dosync = True return res @classmethod def require_resource(self, type, cn, members=None, **kw): """ Create the given resource and return its properties """ create = not self.initialized and not self.develmode res = { 'type': type, 'cn': cn, 'members': members } res.update(kw) if not create: query = get_resource(type, cn) self.log("Resource found: %r" % (query.get('cn','') if isinstance(query, dict) else query)) if len(query) > 0: res = query else: create = True else: self._wipefirst() if create: res = add_resource(type, cn, members, **kw) self.log("Added resource: %r" % (res.get('cn',''))) self.dosync = True return res @classmethod def require_shared_folder(self, type, cn, **kw): """ Create the given shared folder and return its properties """ create = not self.initialized and not self.develmode res = { 'kolabfoldertype': type, 'cn': cn } res.update(kw) if not create: query = get_shared_folder(type, cn) self.log("Folder found: %r" % (query.get('cn','') if isinstance(query, dict) else query)) if len(query) > 0: res = query else: create = True else: self._wipefirst() if create: res = add_shared_folder(type, cn, **kw) self.log("Added shared folder: %r" % (res.get('cn',''))) self.dosync = True return res @classmethod def _wipefirst(self): """ Helper method to remove all data from the Kolab backend """ if not self.wiped: self.log("Wipe data first") wipeall() self.wiped = True def assertIn(self, needle, haystack, message=None): self.assertTrue(needle in haystack, message) def get_conf(self, section, key, default=None): return conf.get(section, key) or default diff --git a/integration/stick/ldap.py b/integration/stick/ldap.py index edc2098..5ccfbb1 100644 --- a/integration/stick/ldap.py +++ b/integration/stick/ldap.py @@ -1,17 +1,18 @@ import time from pykolab.auth import Auth def synchronize(): """ Execute the kolabd synchronization to apply changes in LDAP to IMAP """ auth = Auth() auth.connect() auth.synchronize(mode='_paged_search') time.sleep(1) + auth.disconnect() def domain2dn(domain): """ Utility function to split the given domain name into a DN string """ return 'dc=' + ',dc='.join(domain.split('.')) diff --git a/integration/stick/webadmin.py b/integration/stick/webadmin.py index a8986aa..3b6e651 100644 --- a/integration/stick/webadmin.py +++ b/integration/stick/webadmin.py @@ -1,280 +1,278 @@ import pykolab import time from . import ldap from pykolab import wap_client from pykolab.auth import Auth from httplib import BadStatusLine conf = pykolab.getConf() log = pykolab.getLogger('pytest') def get_instance(): """ Returns a singleton instance to wap_client with an authenticated session """ if not wap_client.session_id: - retry = 0 - while retry < 5: - try: - wap_client.authenticate(conf.get('ldap', 'bind_dn'), conf.get('ldap', 'bind_pw'), conf.get('kolab', 'primary_domain')) - break - except BadStatusLine, e: - print "WAP authenticate error:", str(e) - retry += 1 - time.sleep(2) - except Exception, e: - raise e + wap_client.authenticate(conf.get('ldap', 'bind_dn'), conf.get('ldap', 'bind_pw'), conf.get('kolab', 'primary_domain')) return wap_client def purge_users(): """ Purge all users registered in LDAP from the directory """ client = get_instance() users = wap_client.users_list() for user in users['list']: log.info("Deleting user %s", user) wap_client.user_delete({'id': user}) def purge_resources(): """ Purge all resources registered in LDAP from the directory """ client = get_instance() resources = wap_client.resources_list() for resource in resources['list']: log.info("Deleting resource %s", resource) wap_client.resource_delete({'id': resource}) def purge_shared_folders(): """ Purge all shared folders registered in LDAP from the directory """ client = get_instance() folders = wap_client.sharedfolders_list() for folder in folders['list']: log.info("Deleting shared folder %s", folder) wap_client.sharedfolder_delete({'id': folder}) def get_user(givenname, sn): """ Find user record by name """ client = get_instance() return wap_client.user_find({ 'givenname': givenname, 'sn': sn }) def add_user(givenname, sn, **kw): """ Create a new Kolab user ... """ if givenname == None: raise Exception if givenname == '': raise Exception if sn == None: raise Exception if sn == '': raise Exception primary_domain = conf.get('kolab', 'primary_domain') or 'example.org' user_base_dn = conf.get('ldap', 'kolab_user_base_dn') if not user_base_dn: user_base_dn = 'ou=People,' + ldap.domain2dn(primary_domain) user_details = { 'givenname': givenname, 'sn': sn, 'ou': user_base_dn, 'preferredlanguage': 'en_US', 'userpassword': 'Welcome2KolabSystems' } user_details.update(kw) user_type_id = 0 client = get_instance() user_types = wap_client.user_types_list() for key in user_types['list'].keys(): if user_types['list'][key]['key'] == 'kolab': user_type_id = key user_type_info = user_types['list'][user_type_id]['attributes'] params = { 'user_type_id': user_type_id, } for attribute in user_type_info['form_fields'].keys(): attr_details = user_type_info['form_fields'][attribute] if isinstance(attr_details, dict): if not attr_details.has_key('optional') or attr_details['optional'] == False or user_details.has_key(attribute): params[attribute] = user_details[attribute] elif isinstance(attr_details, list): params[attribute] = user_details[attribute] fvg_params = params fvg_params['object_type'] = 'user' fvg_params['type_id'] = user_type_id fvg_params['attributes'] = [attr for attr in user_type_info['auto_form_fields'].keys() if not attr in params.keys()] result = wap_client.user_add(params) + + if result == False: + raise Exception + result['dn'] = "uid=" + result['uid'] + "," + user_base_dn return result def get_resource(type, cn): """ Find resource record by cn """ client = get_instance() return wap_client.resource_find({ 'cn': cn }) def add_resource(type, cn, members=None, **kw): """ Create a new resource record with an IMAP folder for scheduling ... """ if type == None or type == '': raise Exception if cn == None or cn == '': raise Exception primary_domain = conf.get('kolab', 'primary_domain') or 'example.org' resource_base_dn = conf.get('ldap', 'resource_base_dn') if not resource_base_dn: resource_base_dn = 'ou=Resources,' + ldap.domain2dn(primary_domain) resource_details = { 'cn': cn, 'kolabtargetfolder': "shared/Resources/" + cn + "@" + primary_domain, 'uniquemember': members, 'owner': None, 'ou': resource_base_dn } resource_details.update(kw) client = get_instance() type_id = 0 resource_types = wap_client.resource_types_list() for key in resource_types['list'].keys(): if resource_types['list'][key]['key'] == type: type_id = key if type_id == 0: raise Exception resource_type_info = resource_types['list'][type_id]['attributes'] params = {} for attribute in resource_type_info['form_fields'].keys(): attr_details = resource_type_info['form_fields'][attribute] if isinstance(attr_details, dict): if not attr_details.has_key('optional') or attr_details['optional'] == False or resource_details.has_key(attribute): params[attribute] = resource_details[attribute] elif isinstance(attr_details, list): params[attribute] = resource_details[attribute] fvg_params = params fvg_params['object_type'] = 'resource' fvg_params['type_id'] = type_id fvg_params['attributes'] = [attr for attr in resource_type_info['auto_form_fields'].keys() if not attr in params.keys()] result = wap_client.resource_add(params) + + if result == False: + raise Exception + result['dn'] = "cn=" + result['cn'] + "," + resource_base_dn return result def get_shared_folder(type, cn): client = get_instance() folders = wap_client.sharedfolders_list({ 'search': { 'kolabfoldertype': type }, 'attributes': ['cn','mail','kolabfoldertype','kolabtargetfolder','alias'] }) for dn,folder in folders['list'].items(): if folder.get('kolabfoldertype') == type and folder.get('cn') == cn: return folder return [] def add_shared_folder(type, cn, **kw): """ Create a new shared folder in LDAP and IMAP with read permissions for anyone ... """ if type == None or type == '': raise Exception if cn == None or cn == '': raise Exception primary_domain = conf.get('kolab', 'primary_domain') or 'example.org' params = { 'cn': cn, 'kolabfoldertype': type, 'kolabtargetfolder': 'shared/%s@%s' % (cn, primary_domain), 'acl': [ 'anyone, lrs' ] } if type == 'mail': # TODO: replace with a common normalization functions email = cn.lower().replace(' ', '-') + '@' + primary_domain params['mail'] = email params['kolaballowsmtprecipient'] = [ email ] params.update(kw) type_id = 0 # TODO: fetch this from WAP folder_types = { 'mail': 7, 'event': 2, 'contact': 1, 'file': 6, 'task': 4, 'note': 5, } if folder_types.has_key(type): type_id = folder_types[type] if type_id == 0: raise Exception params['type_id'] = type_id client = get_instance() return wap_client.sharedfolder_add(params)