diff --git a/src/gajim.py b/src/gajim.py index ccb400f66..73f76d7d1 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -813,7 +813,7 @@ class Interface: # FIXME: This *REALLY* are TOO many leves of # indentation! We even need to introduce # a temp var here to make it somehow fit! - for sess in conn.get_sessions(ji): + for sess in conn.get_sessions(ji): if (ji+'/'+resource) != str(sess.jid): continue if sess.enable_encryption: @@ -852,8 +852,10 @@ class Interface: highest = gajim.contacts.get_contact_with_highest_priority(account, jid) is_highest = (highest and highest.resource == resource) - if was_highest and not is_highest: + # disconnect the session from the ctrl if the highest resource has changed + if (was_highest and not is_highest) or (not was_highest and is_highest): ctrl = self.msg_win_mgr.get_control(jid, account) + if ctrl: ctrl.set_session(None) ctrl.contact = highest diff --git a/test/lib/mocks.py b/test/lib/mocks.py index 5790dbde6..f5c74f607 100644 --- a/test/lib/mocks.py +++ b/test/lib/mocks.py @@ -3,9 +3,13 @@ from mock import Mock from common import gajim -class MockConnection(Mock): +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 = {} @@ -13,6 +17,8 @@ class MockConnection(Mock): 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) @@ -37,11 +43,39 @@ 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, *args): + 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 @@ -90,9 +124,12 @@ class MockSession(Mock): self.thread_id = '%0x' % random.randint(0, 10000) def __repr__(self): - print '' % self.thread_id + 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/test_misc_interface.py b/test/test_misc_interface.py index 709632bdb..f1c2baf9f 100644 --- a/test/test_misc_interface.py +++ b/test/test_misc_interface.py @@ -7,7 +7,7 @@ lib.setup_env() from common import gajim from gajim import Interface -from mocks import MockLogger +from mocks import * gajim.logger = MockLogger() Interface() @@ -39,6 +39,180 @@ class TestMiscInterface(unittest.TestCase): assert_matches_all('xmpp:example-node@example.com?message') assert_matches_all('xmpp://guest@example.com/support@example.com?message') +import time +from data import * + +import roster_window + +import notify + +class TestStatusChange(unittest.TestCase): + '''tests gajim.py's incredibly complex handle_event_notify''' + + def setUp(self): + gajim.interface.roster = roster_window.RosterWindow() + + for acc in contacts: + gajim.connections[acc] = MockConnection(acc) + + gajim.interface.roster.fill_contacts_and_groups_dicts(contacts[acc], acc) + gajim.interface.roster.add_account(acc) + gajim.interface.roster.add_account_contacts(acc) + + self.assertEqual(0, len(notify.notifications)) + + def tearDown(self): + gajim.interface.roster.model.clear() + + for acc in contacts: + gajim.contacts.clear_contacts(acc) + + del gajim.interface.roster + + notify.notifications = [] + + def contact_comes_online(self, account, jid, resource, prio): + '''a remote contact comes online''' + gajim.interface.handle_event_notify(account, (jid, 'online', "I'm back!", + resource, prio, None, time.time(), None)) + + contact = None + for c in gajim.contacts.get_contacts(account, jid): + if c.resource == resource: + contact = c + break + + self.assertEqual('online', contact.show) + self.assertEqual("I'm back!", contact.status) + self.assertEqual(prio, contact.priority) + + # the most recent notification is that the contact connected + self.assertEqual('contact_connected', notify.notifications[-1][0]) + + def contact_goes_offline(self, account, jid, resource, prio, + still_exists = True): + '''a remote contact goes offline.''' + gajim.interface.handle_event_notify(account, (jid, 'offline', 'Goodbye!', + resource, prio, None, time.time(), None)) + + contact = None + for c in gajim.contacts.get_contacts(account, jid): + if c.resource == resource: + contact = c + break + + if not still_exists: + self.assert_(contact is None) + return + + self.assertEqual('offline', contact.show) + self.assertEqual('Goodbye!', contact.status) + self.assertEqual(prio, contact.priority) + + self.assertEqual('contact_disconnected', notify.notifications[-1][0]) + + def user_starts_chatting(self, jid, account, resource=None): + '''the user opens a chat window and starts talking''' + ctrl = MockChatControl(jid, account) + win = MockWindow() + win.new_tab(ctrl) + gajim.interface.msg_win_mgr._windows['test'] = win + + if resource: + jid = jid + '/' + resource + + # a basic session is started + session = gajim.connections[account1].make_new_session(jid, + '01234567890abcdef', cls=MockSession) + ctrl.set_session(session) + + return ctrl + + def user_starts_esession(self, jid, resource, account): + '''the user opens a chat window and starts an encrypted session''' + ctrl = self.user_starts_chatting(jid, account, resource) + ctrl.session.status = 'active' + ctrl.session.enable_encryption = True + + return ctrl + + def test_contact_comes_online(self): + jid = 'default1@gajim.org' + + # contact is offline initially + contacts = gajim.contacts.get_contacts(account1, jid) + self.assertEqual(1, len(contacts)) + self.assertEqual('offline', contacts[0].show) + self.assertEqual('', contacts[0].status) + + self.contact_comes_online(account1, jid, 'lowprio', 1) + + def test_contact_goes_offline(self): + jid = 'default1@gajim.org' + + self.contact_comes_online(account1, jid, 'lowprio', 1) + + ctrl = self.user_starts_chatting(jid, account1) + orig_sess = ctrl.session + + self.contact_goes_offline(account1, jid, 'lowprio', 1) + + # session hasn't changed since we were talking to the bare jid + self.assertEqual(orig_sess, ctrl.session) + + def test_two_resources_higher_comes_online(self): + jid = 'default1@gajim.org' + + self.contact_comes_online(account1, jid, 'lowprio', 1) + + ctrl = self.user_starts_chatting(jid, account1) + + self.contact_comes_online(account1, jid, 'highprio', 50) + + # old session was dropped + self.assertEqual(None, ctrl.session) + + def test_two_resources_higher_goes_offline(self): + jid = 'default1@gajim.org' + + self.contact_comes_online(account1, jid, 'lowprio', 1) + self.contact_comes_online(account1, jid, 'highprio', 50) + + ctrl = self.user_starts_chatting(jid, account1) + + self.contact_goes_offline(account1, jid, 'highprio', 50, still_exists = False) + + # old session was dropped + self.assertEqual(None, ctrl.session) + + def test_two_resources_higher_comes_online_with_esession(self): + jid = 'default1@gajim.org' + + self.contact_comes_online(account1, jid, 'lowprio', 1) + + ctrl = self.user_starts_esession(jid, 'lowprio', account1) + + self.contact_comes_online(account1, jid, 'highprio', 50) + + # session was associated with the low priority full jid, so it should + # have been removed from the control + self.assertEqual(None, ctrl.session) + + def test_two_resources_higher_goes_offline_with_esession(self): + jid = 'default1@gajim.org' + + self.contact_comes_online(account1, jid, 'lowprio', 1) + self.contact_comes_online(account1, jid, 'highprio', 50) + + ctrl = self.user_starts_esession(jid, 'highprio', account1) + + self.contact_goes_offline(account1, jid, 'highprio', 50, + still_exists=False) + + # session was associated with the high priority full jid, so it should + # have been removed from the control + self.assertEqual(None, ctrl.session) + if __name__ == '__main__': unittest.main() diff --git a/test/test_roster.py b/test/test_roster.py old mode 100755 new mode 100644 diff --git a/test/test_sessions.py b/test/test_sessions.py index 1699feee7..f8018dfe7 100644 --- a/test/test_sessions.py +++ b/test/test_sessions.py @@ -151,7 +151,7 @@ class TestChatControlSession(unittest.TestCase): jid = 'bct@necronomicorp.com/Gajim' msgtxt = 'testing one two three' - self.sess.control = MockChatControl() + self.sess.control = MockChatControl(jid, account_name) self.receive_chat_msg(jid, msgtxt) @@ -175,7 +175,7 @@ class TestChatControlSession(unittest.TestCase): fjid = jid + '/Gajim' msgtxt = 'testing one two three' - ctrl = MockChatControl() + ctrl = MockChatControl(jid, account_name) gajim.interface.msg_win_mgr = Mock({'get_control': ctrl}) gajim.interface.msg_win_mgr.mockSetExpectation('get_control', expectParams(jid, account_name))