From 559a8c8b1359dfdb1cf2af2928c8c8b7e31e220b Mon Sep 17 00:00:00 2001
From: Brendan Taylor <bct@diffeq.com>
Date: Sat, 9 Aug 2008 06:10:04 +0000
Subject: [PATCH] status change tests, hopefully fix some status change issues

---
 src/gajim.py                |   6 +-
 test/lib/mocks.py           |  43 ++++++++-
 test/test_misc_interface.py | 176 +++++++++++++++++++++++++++++++++++-
 test/test_roster.py         |   0
 test/test_sessions.py       |   4 +-
 5 files changed, 221 insertions(+), 8 deletions(-)
 mode change 100755 => 100644 test/test_roster.py

diff --git a/src/gajim.py b/src/gajim.py
index ccb400f66f..73f76d7d14 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 5790dbde6a..f5c74f6070 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 '<MockSession %s>' % self.thread_id
+		return '<MockSession %s>' % 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 709632bdbd..f1c2baf9ff 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 1699feee74..f8018dfe7c 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))
-- 
GitLab