From a757177e452f869938583014649266d804dfcb79 Mon Sep 17 00:00:00 2001 From: Stephan Erb Date: Sun, 11 Jan 2009 13:49:03 +0000 Subject: Improve code coverage of our testsuites and do some refactoring. * resolver does not depend on GTK anymore * renamed a few modules for consistency * moved all mocks to lib/ * let client_nb test work again. Was broken here There are many failing tests, help appreciated :-) --- test/lib/__init__.py | 10 ++-- test/lib/data.py | 2 + test/lib/gajim_mocks.py | 147 ++++++++++++++++++++++++++++++++++++++++++++++++ test/lib/mocks.py | 145 ----------------------------------------------- test/lib/xmpp_mocks.py | 98 ++++++++++++++++++++++++++++++++ 5 files changed, 253 insertions(+), 149 deletions(-) create mode 100644 test/lib/gajim_mocks.py delete mode 100644 test/lib/mocks.py create mode 100644 test/lib/xmpp_mocks.py (limited to 'test/lib') diff --git a/test/lib/__init__.py b/test/lib/__init__.py index 2b99a7e23..4b5f8ca12 100644 --- a/test/lib/__init__.py +++ b/test/lib/__init__.py @@ -1,5 +1,5 @@ import sys -import os.path +import os import getopt use_x = True @@ -12,7 +12,8 @@ for o, a in opts: gajim_root = os.path.join(os.path.abspath(os.path.dirname(__file__)), '../..') -# look for modules in the CWD, then gajim/test/lib, then gajim/src, then everywhere else +# look for modules in the CWD, then gajim/test/lib, then gajim/src, +# then everywhere else sys.path.insert(1, gajim_root + '/src') sys.path.insert(1, gajim_root + '/test/lib') @@ -23,8 +24,6 @@ configdir = gajim_root + '/test/tmp' import __builtin__ __builtin__._ = lambda x: x -import os - def setup_env(): # wipe config directory if os.path.isdir(configdir): @@ -40,6 +39,9 @@ def setup_env(): # for some reason common.gajim needs to be imported before xmpppy? from common import gajim + import logging + logging.basicConfig() + gajim.DATA_DIR = gajim_root + '/data' gajim.use_x = use_x diff --git a/test/lib/data.py b/test/lib/data.py index e74e9c01b..c713de0ac 100755 --- a/test/lib/data.py +++ b/test/lib/data.py @@ -52,6 +52,7 @@ contacts[account3] = { # 'ask': None, 'groups': [], 'name': None, # 'resources': {}, 'subscription': u'both'} } + # We have contacts that are not in roster but only specified in the metadata metacontact_data = [ [{'account': account3, @@ -75,3 +76,4 @@ metacontact_data = [ 'order': 0}] ] +# vim: se ts=3: diff --git a/test/lib/gajim_mocks.py b/test/lib/gajim_mocks.py new file mode 100644 index 000000000..44b18f037 --- /dev/null +++ b/test/lib/gajim_mocks.py @@ -0,0 +1,147 @@ +''' +Module with dummy classes for Gajim specific unit testing +''' + +from mock import Mock +from common import gajim + +from common.connection_handlers import ConnectionHandlersBase + +class MockConnection(Mock, ConnectionHandlersBase): + def __init__(self, account, *args): + Mock.__init__(self, *args) + ConnectionHandlersBase.__init__(self) + + self.name = account + self.connected = 2 + self.mood = {} + self.activity = {} + self.tune = {} + self.blocked_contacts = {} + self.blocked_groups = {} + self.sessions = {} + + gajim.interface.instances[account] = {'infos': {}, 'disco': {}, + 'gc_config': {}, 'search': {}} + gajim.interface.minimized_controls[account] = {} + gajim.contacts.add_account(account) + gajim.groups[account] = {} + gajim.gc_connected[account] = {} + gajim.automatic_rooms[account] = {} + gajim.newly_added[account] = [] + gajim.to_be_removed[account] = [] + gajim.nicks[account] = gajim.config.get_per('accounts', account, 'name') + gajim.block_signed_in_notifications[account] = True + gajim.sleeper_state[account] = 0 + gajim.encrypted_chats[account] = [] + gajim.last_message_time[account] = {} + gajim.status_before_autoaway[account] = '' + gajim.transport_avatar[account] = {} + gajim.gajim_optional_features[account] = [] + gajim.caps_hash[account] = '' + + gajim.connections[account] = self + +class MockWindow(Mock): + def __init__(self, *args): + Mock.__init__(self, *args) + self.window = Mock() + self._controls = {} + + def get_control(self, jid, account): + try: + return self._controls[account][jid] + except KeyError: + return None + + def has_control(self, jid, acct): + return self.get_control(jid, acct) is not None + + def new_tab(self, ctrl): + account = ctrl.account + jid = ctrl.jid + + if account not in self._controls: + self._controls[account] = {} + + if jid not in self._controls[account]: + self._controls[account][jid] = {} + + self._controls[account][jid] = ctrl + + def __nonzero__(self): + return True + +class MockChatControl(Mock): + def __init__(self, jid, account, *args): + Mock.__init__(self, *args) + + self.jid = jid + self.account = account + + self.parent_win = MockWindow({'get_active_control': self}) + self.session = None + + def set_session(self, sess): + self.session = sess + + def __nonzero__(self): + return True + + def __eq__(self, other): + return self is other + +class MockInterface(Mock): + def __init__(self, *args): + Mock.__init__(self, *args) + gajim.interface = self + self.msg_win_mgr = Mock() + self.roster = Mock() + + self.remote_ctrl = None + self.instances = {} + self.minimized_controls = {} + self.status_sent_to_users = Mock() + + if gajim.use_x: + self.jabber_state_images = {'16': {}, '32': {}, 'opened': {}, + 'closed': {}} + + import gtkgui_helpers + gtkgui_helpers.make_jabber_state_images() + else: + self.jabber_state_images = {'16': Mock(), '32': Mock(), + 'opened': Mock(), 'closed': Mock()} + +class MockLogger(Mock): + def __init__(self): + Mock.__init__(self, {'write': None, 'get_transports_type': {}}) + +class MockContact(Mock): + def __nonzero__(self): + return True + +import random + +class MockSession(Mock): + def __init__(self, conn, jid, thread_id, type_): + Mock.__init__(self) + + self.conn = conn + self.jid = jid + self.type = type_ + self.thread_id = thread_id + + if not self.thread_id: + self.thread_id = '%0x' % random.randint(0, 10000) + + def __repr__(self): + return '' % self.thread_id + + def __nonzero__(self): + return True + + def __eq__(self, other): + return self is other + +# vim: se ts=3: diff --git a/test/lib/mocks.py b/test/lib/mocks.py deleted file mode 100644 index a58d24de8..000000000 --- a/test/lib/mocks.py +++ /dev/null @@ -1,145 +0,0 @@ -# gajim-specific mock objects -from mock import Mock - -from common import gajim - -from common.connection_handlers import ConnectionHandlersBase - -class MockConnection(Mock, ConnectionHandlersBase): - def __init__(self, account, *args): - Mock.__init__(self, *args) - ConnectionHandlersBase.__init__(self) - - self.name = account - self.connected = 2 - self.mood = {} - self.activity = {} - self.tune = {} - self.blocked_contacts = {} - self.blocked_groups = {} - self.sessions = {} - - gajim.interface.instances[account] = {'infos': {}, 'disco': {}, - 'gc_config': {}, 'search': {}} - gajim.interface.minimized_controls[account] = {} - gajim.contacts.add_account(account) - gajim.groups[account] = {} - gajim.gc_connected[account] = {} - gajim.automatic_rooms[account] = {} - gajim.newly_added[account] = [] - gajim.to_be_removed[account] = [] - gajim.nicks[account] = gajim.config.get_per('accounts', account, 'name') - gajim.block_signed_in_notifications[account] = True - gajim.sleeper_state[account] = 0 - gajim.encrypted_chats[account] = [] - gajim.last_message_time[account] = {} - gajim.status_before_autoaway[account] = '' - gajim.transport_avatar[account] = {} - gajim.gajim_optional_features[account] = [] - gajim.caps_hash[account] = '' - - gajim.connections[account] = self - -class MockWindow(Mock): - def __init__(self, *args): - Mock.__init__(self, *args) - self.window = Mock() - self._controls = {} - - def get_control(self, jid, account): - try: - return self._controls[account][jid] - except KeyError: - return None - - def has_control(self, jid, acct): - return self.get_control(jid, acct) is not None - - def new_tab(self, ctrl): - account = ctrl.account - jid = ctrl.jid - - if account not in self._controls: - self._controls[account] = {} - - if jid not in self._controls[account]: - self._controls[account][jid] = {} - - self._controls[account][jid] = ctrl - - def __nonzero__(self): - return True - -class MockChatControl(Mock): - def __init__(self, jid, account, *args): - Mock.__init__(self, *args) - - self.jid = jid - self.account = account - - self.parent_win = MockWindow({'get_active_control': self}) - self.session = None - - def set_session(self, sess): - self.session = sess - - def __nonzero__(self): - return True - - def __eq__(self, other): - return self is other - -class MockInterface(Mock): - def __init__(self, *args): - Mock.__init__(self, *args) - gajim.interface = self - self.msg_win_mgr = Mock() - self.roster = Mock() - - self.remote_ctrl = None - self.instances = {} - self.minimized_controls = {} - self.status_sent_to_users = Mock() - - if gajim.use_x: - self.jabber_state_images = {'16': {}, '32': {}, 'opened': {}, - 'closed': {}} - - import gtkgui_helpers - gtkgui_helpers.make_jabber_state_images() - else: - self.jabber_state_images = {'16': Mock(), '32': Mock(), - 'opened': Mock(), 'closed': Mock()} - -class MockLogger(Mock): - def __init__(self): - Mock.__init__(self, {'write': None, 'get_transports_type': {}}) - -class MockContact(Mock): - def __nonzero__(self): - return True - -import random - -class MockSession(Mock): - def __init__(self, conn, jid, thread_id, type_): - Mock.__init__(self) - - self.conn = conn - self.jid = jid - self.type = type_ - self.thread_id = thread_id - - if not self.thread_id: - self.thread_id = '%0x' % random.randint(0, 10000) - - def __repr__(self): - return '' % self.thread_id - - def __nonzero__(self): - return True - - def __eq__(self, other): - return self is other - -# vim: se ts=3: diff --git a/test/lib/xmpp_mocks.py b/test/lib/xmpp_mocks.py new file mode 100644 index 000000000..4b6b469ad --- /dev/null +++ b/test/lib/xmpp_mocks.py @@ -0,0 +1,98 @@ +''' +Module with dummy classes for unit testing of XMPP and related code. +''' + +import threading, time + +from mock import Mock + +from common.xmpp import idlequeue +from common.xmpp.plugin import PlugIn + +IDLEQUEUE_INTERVAL = 0.2 # polling interval. 200ms is used in Gajim as default +IDLEMOCK_TIMEOUT = 30 # how long we wait for an event + +class IdleQueueThread(threading.Thread): + ''' + Thread for regular processing of idlequeue. + ''' + def __init__(self): + self.iq = idlequeue.IdleQueue() + self.stop = threading.Event() # Event to stop the thread main loop. + self.stop.clear() + threading.Thread.__init__(self) + + def run(self): + while not self.stop.isSet(): + self.iq.process() + time.sleep(IDLEQUEUE_INTERVAL) + + def stop_thread(self): + self.stop.set() + + +class IdleMock: + ''' + Serves as template for testing objects that are normally controlled by GUI. + Allows to wait for asynchronous callbacks with wait() method. + ''' + def __init__(self): + self._event = threading.Event() + self._event.clear() + + def wait(self): + ''' + Block until some callback sets the event and clearing the event + subsequently. + Returns True if event was set, False on timeout + ''' + self._event.wait(IDLEMOCK_TIMEOUT) + if self._event.is_set(): + self._event.clear() + return True + else: + return False + + def set_event(self): + self._event.set() + + +class MockConnection(IdleMock, Mock): + ''' + Class simulating Connection class from src/common/connection.py + + It is derived from Mock in order to avoid defining all methods + from real Connection that are called from NBClient or Dispatcher + ( _event_dispatcher for example) + ''' + + def __init__(self, *args): + self.connect_succeeded = True + IdleMock.__init__(self) + Mock.__init__(self, *args) + + def on_connect(self, success, *args): + ''' + Method called after connecting - after receiving + from server (NOT after TLS stream restart) or connect failure + ''' + self.connect_succeeded = success + self.set_event() + + + def on_auth(self, con, auth): + ''' + Method called after authentication, regardless of the result. + + :Parameters: + con : NonBlockingClient + reference to authenticated object + auth : string + type of authetication in case of success ('old_auth', 'sasl') or + None in case of auth failure + ''' + self.auth_connection = con + self.auth = auth + self.set_event() + +# vim: se ts=3: -- cgit v1.2.3