Redistribute responsibility: Let contact instances check if features are supported
This commit is contained in:
		
							parent
							
								
									3295b08b26
								
							
						
					
					
						commit
						c7ff97703f
					
				
					 5 changed files with 188 additions and 262 deletions
				
			
		| 
						 | 
					@ -39,51 +39,30 @@ import gajim
 | 
				
			||||||
import helpers
 | 
					import helpers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from common.xmpp import NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION, NS_CHATSTATES
 | 
					from common.xmpp import NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION, NS_CHATSTATES
 | 
				
			||||||
 | 
					 | 
				
			||||||
# Features where we cannot safely assume that the other side supports them
 | 
					# Features where we cannot safely assume that the other side supports them
 | 
				
			||||||
FEATURE_BLACKLIST = [NS_CHATSTATES, NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION]
 | 
					FEATURE_BLACKLIST = [NS_CHATSTATES, NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class AbstractClientCaps(object):
 | 
					class AbstractClientCaps(object):
 | 
				
			||||||
	'''
 | 
						'''
 | 
				
			||||||
	Base class representing a client and its capabilities as advertised by
 | 
						Base class representing a client and its capabilities as advertised by
 | 
				
			||||||
	a caps tag in a presence
 | 
						a caps tag in a presence
 | 
				
			||||||
	'''
 | 
						'''
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	def __init__(self, caps_cache, caps_hash, node):
 | 
						def __init__(self, caps_hash, node):
 | 
				
			||||||
		self._caps_cache = caps_cache
 | 
					 | 
				
			||||||
		self._hash = caps_hash
 | 
							self._hash = caps_hash
 | 
				
			||||||
		self._node = node
 | 
							self._node = node
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
	def query_client_of_jid_if_unknown(self, connection, jid):
 | 
						def get_discover_strategy(self):
 | 
				
			||||||
		'''
 | 
							return self._discover
 | 
				
			||||||
		Asynchronously query the give jid for its (node, ver, exts) caps data
 | 
					 | 
				
			||||||
		using a disco query.
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		Query will only be sent if the data is not already cached.
 | 
					 | 
				
			||||||
		'''
 | 
					 | 
				
			||||||
		q = self._lookup_in_cache()
 | 
					 | 
				
			||||||
		if q.queried == 0:
 | 
					 | 
				
			||||||
			self._discover(connection, jid)
 | 
					 | 
				
			||||||
			q.queried = 1
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
	def contains_feature(self, requested_feature):
 | 
					 | 
				
			||||||
		''' Returns true if these capabilities contain the given feature '''
 | 
					 | 
				
			||||||
		cach_entry = self._lookup_in_cache()
 | 
					 | 
				
			||||||
		supported_features = cach_entry.features
 | 
					 | 
				
			||||||
		if requested_feature in supported_features:
 | 
					 | 
				
			||||||
			return True
 | 
					 | 
				
			||||||
		elif supported_features == [] and cach_entry.queried in (0, 1):
 | 
					 | 
				
			||||||
			# assume feature is supported, if not blacklisted
 | 
					 | 
				
			||||||
			return requested_feature not in FEATURE_BLACKLIST
 | 
					 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			return False
 | 
					 | 
				
			||||||
							
 | 
												
 | 
				
			||||||
	def _discover(self, connection, jid):
 | 
						def _discover(self, connection, jid):
 | 
				
			||||||
		''' To be implemented by subclassess '''
 | 
							''' To be implemented by subclassess '''
 | 
				
			||||||
		raise NotImplementedError()
 | 
							raise NotImplementedError()
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	def _lookup_in_cache(self):
 | 
						def get_cache_lookup_strategy(self):
 | 
				
			||||||
 | 
							return self._lookup_in_cache
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						def _lookup_in_cache(self, caps_cache):
 | 
				
			||||||
		''' To be implemented by subclassess '''
 | 
							''' To be implemented by subclassess '''
 | 
				
			||||||
		raise NotImplementedError()
 | 
							raise NotImplementedError()
 | 
				
			||||||
					
 | 
										
 | 
				
			||||||
| 
						 | 
					@ -91,13 +70,13 @@ class AbstractClientCaps(object):
 | 
				
			||||||
class ClientCaps(AbstractClientCaps):
 | 
					class ClientCaps(AbstractClientCaps):
 | 
				
			||||||
	''' The current XEP-115 implementation '''
 | 
						''' The current XEP-115 implementation '''
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	def __init__(self, caps_cache, caps_hash, node, hash_method):
 | 
						def __init__(self, caps_hash, node, hash_method):
 | 
				
			||||||
		AbstractClientCaps.__init__(self, caps_cache, caps_hash, node)
 | 
							AbstractClientCaps.__init__(self, caps_hash, node)
 | 
				
			||||||
		assert hash_method != 'old'
 | 
							assert hash_method != 'old'
 | 
				
			||||||
		self._hash_method = hash_method
 | 
							self._hash_method = hash_method
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	def _lookup_in_cache(self):
 | 
						def _lookup_in_cache(self, caps_cache):
 | 
				
			||||||
		return self._caps_cache[(self._hash_method, self._hash)]
 | 
							return caps_cache[(self._hash_method, self._hash)]
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	def _discover(self, connection, jid):
 | 
						def _discover(self, connection, jid):
 | 
				
			||||||
		connection.discoverInfo(jid, '%s#%s' % (self._node, self._hash))
 | 
							connection.discoverInfo(jid, '%s#%s' % (self._node, self._hash))
 | 
				
			||||||
| 
						 | 
					@ -106,11 +85,11 @@ class ClientCaps(AbstractClientCaps):
 | 
				
			||||||
class OldClientCaps(AbstractClientCaps):
 | 
					class OldClientCaps(AbstractClientCaps):
 | 
				
			||||||
	''' Old XEP-115 implemtation. Kept around for background competability.  '''
 | 
						''' Old XEP-115 implemtation. Kept around for background competability.  '''
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	def __init__(self, caps_cache, caps_hash, node):
 | 
						def __init__(self, caps_hash, node):
 | 
				
			||||||
		AbstractClientCaps.__init__(self, caps_cache, caps_hash, node)
 | 
							AbstractClientCaps.__init__(self, caps_hash, node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _lookup_in_cache(self):
 | 
						def _lookup_in_cache(self, caps_cache):
 | 
				
			||||||
		return self._caps_cache[('old', self._node + '#' + self._hash)]
 | 
							return caps_cache[('old', self._node + '#' + self._hash)]
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	def _discover(self, connection, jid):
 | 
						def _discover(self, connection, jid):
 | 
				
			||||||
		connection.discoverInfo(jid)
 | 
							connection.discoverInfo(jid)
 | 
				
			||||||
| 
						 | 
					@ -125,32 +104,19 @@ class NullClientCaps(AbstractClientCaps):
 | 
				
			||||||
	''' 
 | 
						''' 
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	def __init__(self):
 | 
						def __init__(self):
 | 
				
			||||||
		pass
 | 
							AbstractClientCaps.__init__(self, None, None)
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	def query_client_of_jid_if_unknown(self, connection, jid):
 | 
						def _lookup_in_cache(self, caps_cache):
 | 
				
			||||||
		pass
 | 
							return caps_cache[('old', '')]
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	def contains_feature(self, feature):
 | 
						def _discover(self, connection, jid):
 | 
				
			||||||
		return feature not in FEATURE_BLACKLIST
 | 
							pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CapsCache(object):
 | 
					class CapsCache(object):
 | 
				
			||||||
	''' This object keeps the mapping between caps data and real disco
 | 
						''' 
 | 
				
			||||||
 | 
						This object keeps the mapping between caps data and real disco
 | 
				
			||||||
	features they represent, and provides simple way to query that info.
 | 
						features they represent, and provides simple way to query that info.
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	It is application-wide, that is there's one object for all
 | 
					 | 
				
			||||||
	connections.
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	Goals:
 | 
					 | 
				
			||||||
	 * handle storing/retrieving info from database
 | 
					 | 
				
			||||||
	 * cache info in memory
 | 
					 | 
				
			||||||
	 * expose simple interface
 | 
					 | 
				
			||||||
	 
 | 
					 | 
				
			||||||
	Properties:
 | 
					 | 
				
			||||||
	 * one object for all connections (move to logger.py?)
 | 
					 | 
				
			||||||
	 * store info efficiently (a set() of urls -- we can assume there won't be
 | 
					 | 
				
			||||||
	   too much of these, ensure that (X,Y,Z1) and (X,Y,Z2) has different
 | 
					 | 
				
			||||||
	   features.
 | 
					 | 
				
			||||||
	'''
 | 
						'''
 | 
				
			||||||
	def __init__(self, logger=None):
 | 
						def __init__(self, logger=None):
 | 
				
			||||||
		''' Create a cache for entity capabilities. '''
 | 
							''' Create a cache for entity capabilities. '''
 | 
				
			||||||
| 
						 | 
					@ -219,15 +185,14 @@ class CapsCache(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			def update(self, identities, features):
 | 
								def update(self, identities, features):
 | 
				
			||||||
				# NOTE: self refers to CapsCache object, not to CacheItem
 | 
									# NOTE: self refers to CapsCache object, not to CacheItem
 | 
				
			||||||
				self.identities=identities
 | 
									self.identities = identities
 | 
				
			||||||
				self.features=features
 | 
									self.features = features
 | 
				
			||||||
				self._logger.add_caps_entry(self.hash_method, self.hash,
 | 
									self._logger.add_caps_entry(self.hash_method, self.hash,
 | 
				
			||||||
					identities, features)
 | 
										identities, features)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		self.__CacheItem = CacheItem
 | 
							self.__CacheItem = CacheItem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# prepopulate data which we are sure of; note: we do not log these info
 | 
							# prepopulate data which we are sure of; note: we do not log these info
 | 
				
			||||||
 | 
					 | 
				
			||||||
		for account in gajim.connections:
 | 
							for account in gajim.connections:
 | 
				
			||||||
			gajimcaps = self[('sha-1', gajim.caps_hash[account])]
 | 
								gajimcaps = self[('sha-1', gajim.caps_hash[account])]
 | 
				
			||||||
			gajimcaps.identities = [gajim.gajim_identity]
 | 
								gajimcaps.identities = [gajim.gajim_identity]
 | 
				
			||||||
| 
						 | 
					@ -257,48 +222,19 @@ class CapsCache(object):
 | 
				
			||||||
		self.__cache[(hash_method, hash_)] = x
 | 
							self.__cache[(hash_method, hash_)] = x
 | 
				
			||||||
		return x
 | 
							return x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def preload(self, con, jid, node, hash_method, hash_):
 | 
						def query_client_of_jid_if_unknown(self, connection, jid, client_caps):
 | 
				
			||||||
		''' Preload data about (node, ver, exts) caps using disco
 | 
							''' Preload data about (node, ver, exts) caps using disco
 | 
				
			||||||
		query to jid using proper connection. Don't query if
 | 
							query to jid using proper connection. Don't query if
 | 
				
			||||||
		the data is already in cache. '''
 | 
							the data is already in cache. '''
 | 
				
			||||||
		if hash_method == 'old':
 | 
							lookup_cache_item = client_caps.get_cache_lookup_strategy()
 | 
				
			||||||
			q = self[(hash_method, node + '#' + hash_)]
 | 
							q = lookup_cache_item(self)	
 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			q = self[(hash_method, hash_)]
 | 
					 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		if q.queried==0:
 | 
							if q.queried == 0:
 | 
				
			||||||
			# do query for bare node+hash pair
 | 
								# do query for bare node+hash pair
 | 
				
			||||||
			# this will create proper object
 | 
								# this will create proper object
 | 
				
			||||||
			q.queried=1
 | 
								q.queried = 1
 | 
				
			||||||
			if hash_method == 'old':
 | 
								discover = client_caps.get_discover_strategy()
 | 
				
			||||||
				con.discoverInfo(jid)
 | 
								discover(connection, jid)
 | 
				
			||||||
			else:
 | 
					 | 
				
			||||||
				con.discoverInfo(jid, '%s#%s' % (node, hash_))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def is_supported(self, contact, feature):
 | 
					 | 
				
			||||||
		if not contact:
 | 
					 | 
				
			||||||
			return False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Unfortunately, if all resources are offline, the contact
 | 
					 | 
				
			||||||
		# includes the last resource that was online. Check for its
 | 
					 | 
				
			||||||
		# show, so we can be sure it's existant. Otherwise, we still
 | 
					 | 
				
			||||||
		# return caps for a contact that has no resources left.
 | 
					 | 
				
			||||||
		if contact.show == 'offline':
 | 
					 | 
				
			||||||
			return False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# FIXME: We assume everything is supported if we got no caps.
 | 
					 | 
				
			||||||
		#	 This is the "Asterix way", after 0.12 release, I will
 | 
					 | 
				
			||||||
		#	 likely implement a fallback to disco (could be disabled
 | 
					 | 
				
			||||||
		#	 for mobile users who pay for traffic)
 | 
					 | 
				
			||||||
		if contact.caps_hash_method == 'old':
 | 
					 | 
				
			||||||
			features = self[(contact.caps_hash_method, contact.caps_node + '#' + \
 | 
					 | 
				
			||||||
				contact.caps_hash)].features
 | 
					 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			features = self[(contact.caps_hash_method, contact.caps_hash)].features
 | 
					 | 
				
			||||||
		if feature in features or features == []:
 | 
					 | 
				
			||||||
			return True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return False
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
gajim.capscache = CapsCache(gajim.logger)
 | 
					gajim.capscache = CapsCache(gajim.logger)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,12 +30,15 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import common.gajim
 | 
					import common.gajim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from common.caps import NullClientCaps, FEATURE_BLACKLIST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Contact(object):
 | 
					class Contact(object):
 | 
				
			||||||
	'''Information concerning each contact'''
 | 
						'''Information concerning each contact'''
 | 
				
			||||||
	def __init__(self, jid='', name='', groups=[], show='', status='', sub='',
 | 
						def __init__(self, jid='', name='', groups=[], show='', status='', sub='',
 | 
				
			||||||
	ask='', resource='', priority=0, keyID='', caps_node=None,
 | 
						ask='', resource='', priority=0, keyID='', client_caps=None, caps_cache=None,
 | 
				
			||||||
	caps_hash_method=None, caps_hash=None, our_chatstate=None, chatstate=None,
 | 
						our_chatstate=None, chatstate=None, last_status_time=None, msg_id = None,
 | 
				
			||||||
	last_status_time=None, msg_id = None, composing_xep = None,	mood={}, tune={},
 | 
						composing_xep = None,	mood={}, tune={},
 | 
				
			||||||
	activity={}):
 | 
						activity={}):
 | 
				
			||||||
		self.jid = jid
 | 
							self.jid = jid
 | 
				
			||||||
		self.name = name
 | 
							self.name = name
 | 
				
			||||||
| 
						 | 
					@ -49,11 +52,9 @@ class Contact(object):
 | 
				
			||||||
		self.priority = priority
 | 
							self.priority = priority
 | 
				
			||||||
		self.keyID = keyID
 | 
							self.keyID = keyID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Capabilities; filled by caps.py/ConnectionCaps object
 | 
							# Entity Capabilities
 | 
				
			||||||
		# every time it gets these from presence stanzas
 | 
							self._client_caps = client_caps or NullClientCaps()
 | 
				
			||||||
		self.caps_node = caps_node
 | 
							self._caps_cache = caps_cache or common.gajim.capscache 
 | 
				
			||||||
		self.caps_hash_method = caps_hash_method
 | 
					 | 
				
			||||||
		self.caps_hash = caps_hash
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# please read xep-85 http://www.xmpp.org/extensions/xep-0085.html
 | 
							# please read xep-85 http://www.xmpp.org/extensions/xep-0085.html
 | 
				
			||||||
		# we keep track of xep85 support with the peer by three extra states:
 | 
							# we keep track of xep85 support with the peer by three extra states:
 | 
				
			||||||
| 
						 | 
					@ -135,31 +136,33 @@ class Contact(object):
 | 
				
			||||||
		return False
 | 
							return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _set_supported_caps(self, value):
 | 
						def supports(self, requested_feature):
 | 
				
			||||||
		'''
 | 
							if self.show == 'offline':
 | 
				
			||||||
		Set an EntityCapabilities object
 | 
								# Unfortunately, if all resources are offline, the contact
 | 
				
			||||||
		'''
 | 
								# includes the last resource that was online. Check for its
 | 
				
			||||||
		self._caps = value
 | 
								# show, so we can be sure it's existant. Otherwise, we still
 | 
				
			||||||
 | 
								# return caps for a contact that has no resources left.
 | 
				
			||||||
 | 
								return False
 | 
				
			||||||
 | 
							else:
 | 
				
			||||||
 | 
								return self._client_supports(requested_feature)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _get_supported_caps(self):
 | 
						def _client_supports(self, requested_feature):
 | 
				
			||||||
		'''
 | 
							lookup_item = self._client_caps.get_cache_lookup_strategy()
 | 
				
			||||||
		Returns a function which delegates to the EntityCapabilites	support checker
 | 
							cache_item = lookup_item(self._caps_cache)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		This allows easy checks like:
 | 
							supported_features = cache_item.features
 | 
				
			||||||
			if contact.supports(NS_COOL_FEATURE): ...
 | 
							if requested_feature in supported_features:
 | 
				
			||||||
		'''
 | 
								return True
 | 
				
			||||||
		def test(feature):
 | 
							elif supported_features == [] and cache_item.queried in (0, 1):
 | 
				
			||||||
			if self.show == 'offline':
 | 
								# assume feature is supported, if we don't know yet, what the client
 | 
				
			||||||
				# Unfortunately, if all resources are offline, the contact
 | 
								# is capable of
 | 
				
			||||||
				# includes the last resource that was online. Check for its
 | 
								return requested_feature not in FEATURE_BLACKLIST
 | 
				
			||||||
				# show, so we can be sure it's existant. Otherwise, we still
 | 
							else:
 | 
				
			||||||
				# return caps for a contact that has no resources left.
 | 
								return False
 | 
				
			||||||
				return False
 | 
					 | 
				
			||||||
			else:
 | 
					 | 
				
			||||||
				return self._caps.contains_feature(feature)
 | 
					 | 
				
			||||||
		return test
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	supports = property(_get_supported_caps, _set_supported_caps)
 | 
						def set_supported_client_caps(self, client_caps):
 | 
				
			||||||
 | 
							''' Set an EntityCapabilities object '''
 | 
				
			||||||
 | 
							self._client_caps = client_caps
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GC_Contact:
 | 
					class GC_Contact:
 | 
				
			||||||
| 
						 | 
					@ -175,9 +178,11 @@ class GC_Contact:
 | 
				
			||||||
		self.affiliation = affiliation
 | 
							self.affiliation = affiliation
 | 
				
			||||||
		self.jid = jid
 | 
							self.jid = jid
 | 
				
			||||||
		self.resource = resource
 | 
							self.resource = resource
 | 
				
			||||||
		self.caps_node = None
 | 
							
 | 
				
			||||||
		self.caps_hash_method = None
 | 
							# Entity Capabilities
 | 
				
			||||||
		self.caps_hash = None
 | 
							self._client_caps = NullClientCaps()
 | 
				
			||||||
 | 
							self._caps_cache = common.gajim.capscache 
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		self.our_chatstate = our_chatstate
 | 
							self.our_chatstate = our_chatstate
 | 
				
			||||||
		self.composing_xep = composing_xep
 | 
							self.composing_xep = composing_xep
 | 
				
			||||||
		self.chatstate = chatstate
 | 
							self.chatstate = chatstate
 | 
				
			||||||
| 
						 | 
					@ -188,31 +193,33 @@ class GC_Contact:
 | 
				
			||||||
	def get_shown_name(self):
 | 
						def get_shown_name(self):
 | 
				
			||||||
		return self.name
 | 
							return self.name
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	def _set_supported_caps(self, value):
 | 
						def supports(self, requested_feature):
 | 
				
			||||||
		'''
 | 
							if self.show == 'offline':
 | 
				
			||||||
		Set an EntityCapabilities object
 | 
								# Unfortunately, if all resources are offline, the contact
 | 
				
			||||||
		'''
 | 
								# includes the last resource that was online. Check for its
 | 
				
			||||||
		self._caps = value
 | 
								# show, so we can be sure it's existant. Otherwise, we still
 | 
				
			||||||
 | 
								# return caps for a contact that has no resources left.
 | 
				
			||||||
 | 
								return False
 | 
				
			||||||
 | 
							else:
 | 
				
			||||||
 | 
								return self._client_supports(requested_feature)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _get_supported_caps(self):
 | 
						def _client_supports(self, requested_feature):
 | 
				
			||||||
		'''
 | 
							lookup_item = self._client_caps.get_cache_lookup_strategy()
 | 
				
			||||||
		Returns a function which delegates to the EntityCapabilites	support checker
 | 
							cache_item = lookup_item(self._caps_cache)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		This allows easy checks like:
 | 
							supported_features = cache_item.features
 | 
				
			||||||
			if contact.supports(NS_COOL_FEATURE): ...
 | 
							if requested_feature in supported_features:
 | 
				
			||||||
		'''
 | 
								return True
 | 
				
			||||||
		def test(feature):
 | 
							elif supported_features == [] and cache_item.queried in (0, 1):
 | 
				
			||||||
			if self.show == 'offline':
 | 
								# assume feature is supported, if we don't know yet, what the client
 | 
				
			||||||
				# Unfortunately, if all resources are offline, the contact
 | 
								# is capable of
 | 
				
			||||||
				# includes the last resource that was online. Check for its
 | 
								return requested_feature not in FEATURE_BLACKLIST
 | 
				
			||||||
				# show, so we can be sure it's existant. Otherwise, we still
 | 
							else:
 | 
				
			||||||
				# return caps for a contact that has no resources left.
 | 
								return False
 | 
				
			||||||
				return False
 | 
					 | 
				
			||||||
			else:
 | 
					 | 
				
			||||||
				return self._caps.contains_feature(feature)
 | 
					 | 
				
			||||||
		return test
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	supports = property(_get_supported_caps, _set_supported_caps)
 | 
						def set_supported_client_caps(self, client_caps):
 | 
				
			||||||
 | 
							''' Set an EntityCapabilities object '''
 | 
				
			||||||
 | 
							self._client_caps = client_caps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Contacts:
 | 
					class Contacts:
 | 
				
			||||||
	'''Information concerning all contacts and groupchat contacts'''
 | 
						'''Information concerning all contacts and groupchat contacts'''
 | 
				
			||||||
| 
						 | 
					@ -246,8 +253,8 @@ class Contacts:
 | 
				
			||||||
		del self._metacontacts_tags[account]
 | 
							del self._metacontacts_tags[account]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def create_contact(self, jid='', name='', groups=[], show='', status='',
 | 
						def create_contact(self, jid='', name='', groups=[], show='', status='',
 | 
				
			||||||
		sub='', ask='', resource='', priority=0, keyID='', caps_node=None,
 | 
							sub='', ask='', resource='', priority=0, keyID='', client_caps=None,
 | 
				
			||||||
		caps_hash_method=None, caps_hash=None, our_chatstate=None,
 | 
							caps_cache=None, our_chatstate=None,
 | 
				
			||||||
		chatstate=None, last_status_time=None, composing_xep=None,
 | 
							chatstate=None, last_status_time=None, composing_xep=None,
 | 
				
			||||||
		mood={}, tune={}, activity={}):
 | 
							mood={}, tune={}, activity={}):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -259,8 +266,8 @@ class Contacts:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return Contact(jid=jid, name=name, groups=groups_unique, show=show,
 | 
							return Contact(jid=jid, name=name, groups=groups_unique, show=show,
 | 
				
			||||||
			status=status, sub=sub, ask=ask, resource=resource, priority=priority,
 | 
								status=status, sub=sub, ask=ask, resource=resource, priority=priority,
 | 
				
			||||||
			keyID=keyID, caps_node=caps_node, caps_hash_method=caps_hash_method,
 | 
								keyID=keyID, client_caps=client_caps, caps_cache=caps_cache,
 | 
				
			||||||
			caps_hash=caps_hash, our_chatstate=our_chatstate, chatstate=chatstate,
 | 
								our_chatstate=our_chatstate, chatstate=chatstate,
 | 
				
			||||||
			last_status_time=last_status_time, composing_xep=composing_xep,
 | 
								last_status_time=last_status_time, composing_xep=composing_xep,
 | 
				
			||||||
			mood=mood, tune=tune, activity=activity)
 | 
								mood=mood, tune=tune, activity=activity)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -269,8 +276,8 @@ class Contacts:
 | 
				
			||||||
			groups=contact.groups, show=contact.show, status=contact.status,
 | 
								groups=contact.groups, show=contact.show, status=contact.status,
 | 
				
			||||||
			sub=contact.sub, ask=contact.ask, resource=contact.resource,
 | 
								sub=contact.sub, ask=contact.ask, resource=contact.resource,
 | 
				
			||||||
			priority=contact.priority, keyID=contact.keyID,
 | 
								priority=contact.priority, keyID=contact.keyID,
 | 
				
			||||||
			caps_node=contact.caps_node, caps_hash_method=contact.caps_hash_method,
 | 
								client_caps=contact._client_caps, caps_cache=contact._caps_cache,
 | 
				
			||||||
			caps_hash=contact.caps_hash, our_chatstate=contact.our_chatstate,
 | 
								our_chatstate=contact.our_chatstate,
 | 
				
			||||||
			chatstate=contact.chatstate, last_status_time=contact.last_status_time)
 | 
								chatstate=contact.chatstate, last_status_time=contact.last_status_time)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def add_contact(self, account, contact):
 | 
						def add_contact(self, account, contact):
 | 
				
			||||||
| 
						 | 
					@ -640,9 +647,8 @@ class Contacts:
 | 
				
			||||||
		jid = gc_contact.get_full_jid()
 | 
							jid = gc_contact.get_full_jid()
 | 
				
			||||||
		return Contact(jid=jid, resource=gc_contact.resource,
 | 
							return Contact(jid=jid, resource=gc_contact.resource,
 | 
				
			||||||
			name=gc_contact.name, groups=[], show=gc_contact.show,
 | 
								name=gc_contact.name, groups=[], show=gc_contact.show,
 | 
				
			||||||
			status=gc_contact.status, sub='none', caps_node=gc_contact.caps_node,
 | 
								status=gc_contact.status, sub='none', client_caps=gc_contact._client_caps,
 | 
				
			||||||
			caps_hash_method=gc_contact.caps_hash_method,
 | 
								caps_cache=gc_contact._caps_cache)
 | 
				
			||||||
			caps_hash=gc_contact.caps_hash)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def create_gc_contact(self, room_jid='', name='', show='', status='',
 | 
						def create_gc_contact(self, room_jid='', name='', show='', status='',
 | 
				
			||||||
		role='', affiliation='', jid='', resource=''):
 | 
							role='', affiliation='', jid='', resource=''):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,8 +32,6 @@ import logging
 | 
				
			||||||
import locale
 | 
					import locale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import config
 | 
					import config
 | 
				
			||||||
from contacts import Contacts
 | 
					 | 
				
			||||||
from events import Events
 | 
					 | 
				
			||||||
import xmpp
 | 
					import xmpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
try:
 | 
					try:
 | 
				
			||||||
| 
						 | 
					@ -101,6 +99,9 @@ else:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
os_info = None # used to cache os information
 | 
					os_info = None # used to cache os information
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from contacts import Contacts
 | 
				
			||||||
 | 
					from events import Events
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gmail_domains = ['gmail.com', 'googlemail.com']
 | 
					gmail_domains = ['gmail.com', 'googlemail.com']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
transport_type = {} # list the type of transport
 | 
					transport_type = {} # list the type of transport
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,11 +6,11 @@ import unittest
 | 
				
			||||||
import lib
 | 
					import lib
 | 
				
			||||||
lib.setup_env()
 | 
					lib.setup_env()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from common import gajim
 | 
				
			||||||
from common import helpers
 | 
					from common import helpers
 | 
				
			||||||
from common.contacts import Contact
 | 
					 | 
				
			||||||
from common.xmpp import NS_MUC, NS_PING, NS_XHTML_IM
 | 
					from common.xmpp import NS_MUC, NS_PING, NS_XHTML_IM
 | 
				
			||||||
 | 
					 | 
				
			||||||
from common.caps import CapsCache, ClientCaps, OldClientCaps
 | 
					from common.caps import CapsCache, ClientCaps, OldClientCaps
 | 
				
			||||||
 | 
					from common.contacts import Contact
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from mock import Mock
 | 
					from mock import Mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,7 @@ class CommonCapsTest(unittest.TestCase):
 | 
				
			||||||
	def setUp(self):
 | 
						def setUp(self):
 | 
				
			||||||
		self.caps_method = 'sha-1'
 | 
							self.caps_method = 'sha-1'
 | 
				
			||||||
		self.caps_hash = 'm3P2WeXPMGVH2tZPe7yITnfY0Dw='
 | 
							self.caps_hash = 'm3P2WeXPMGVH2tZPe7yITnfY0Dw='
 | 
				
			||||||
		self.caps = (self.caps_method, self.caps_hash)
 | 
							self.client_caps = (self.caps_method, self.caps_hash)
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		self.node = "http://gajim.org"
 | 
							self.node = "http://gajim.org"
 | 
				
			||||||
		self.identity = {'category': 'client', 'type': 'pc', 'name':'Gajim'}
 | 
							self.identity = {'category': 'client', 'type': 'pc', 'name':'Gajim'}
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,10 @@ class CommonCapsTest(unittest.TestCase):
 | 
				
			||||||
		self.logger = Mock(returnValues={"iter_caps_data":db_caps_cache})
 | 
							self.logger = Mock(returnValues={"iter_caps_data":db_caps_cache})
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		self.cc = CapsCache(self.logger)
 | 
							self.cc = CapsCache(self.logger)
 | 
				
			||||||
 | 
							# This is a temporary hack required by the way contacts rely on the 
 | 
				
			||||||
 | 
							# existance of a cache. Hopefully this can be refactored to work via
 | 
				
			||||||
 | 
							# dependency injection
 | 
				
			||||||
 | 
							gajim.capscache = self.cc
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
class TestCapsCache(CommonCapsTest):
 | 
					class TestCapsCache(CommonCapsTest):
 | 
				
			||||||
| 
						 | 
					@ -42,13 +46,13 @@ class TestCapsCache(CommonCapsTest):
 | 
				
			||||||
	def test_set_retrieve(self):
 | 
						def test_set_retrieve(self):
 | 
				
			||||||
		''' Test basic set / retrieve cycle '''
 | 
							''' Test basic set / retrieve cycle '''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		self.cc[self.caps].identities = self.identities
 | 
							self.cc[self.client_caps].identities = self.identities
 | 
				
			||||||
		self.cc[self.caps].features = self.features
 | 
							self.cc[self.client_caps].features = self.features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		self.assert_(NS_MUC in self.cc[self.caps].features)
 | 
							self.assert_(NS_MUC in self.cc[self.client_caps].features)
 | 
				
			||||||
		self.assert_(NS_PING not in self.cc[self.caps].features)
 | 
							self.assert_(NS_PING not in self.cc[self.client_caps].features)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		identities = self.cc[self.caps].identities
 | 
							identities = self.cc[self.client_caps].identities
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		self.assertEqual(1, len(identities))
 | 
							self.assertEqual(1, len(identities))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,9 +61,9 @@ class TestCapsCache(CommonCapsTest):
 | 
				
			||||||
		self.assertEqual('pc', identity['type'])
 | 
							self.assertEqual('pc', identity['type'])
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
	def test_update(self):
 | 
						def test_update(self):
 | 
				
			||||||
		''' Test caps update gets logged into db '''
 | 
							''' Test client_caps update gets logged into db '''
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		item = self.cc[self.caps]
 | 
							item = self.cc[self.client_caps]
 | 
				
			||||||
		item.update(self.identities, self.features)
 | 
							item.update(self.identities, self.features)
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		self.logger.mockCheckCall(0, "add_caps_entry", self.caps_method,
 | 
							self.logger.mockCheckCall(0, "add_caps_entry", self.caps_method,
 | 
				
			||||||
| 
						 | 
					@ -67,46 +71,31 @@ class TestCapsCache(CommonCapsTest):
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
	def test_initialize_from_db(self):
 | 
						def test_initialize_from_db(self):
 | 
				
			||||||
		''' Read cashed dummy data from db ''' 
 | 
							''' Read cashed dummy data from db ''' 
 | 
				
			||||||
		self.assertEqual(self.cc[self.caps].queried, 0)
 | 
							self.assertEqual(self.cc[self.client_caps].queried, 0)
 | 
				
			||||||
		self.cc.initialize_from_db()
 | 
							self.cc.initialize_from_db()
 | 
				
			||||||
		self.assertEqual(self.cc[self.caps].queried, 2)
 | 
							self.assertEqual(self.cc[self.client_caps].queried, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def test_preload_triggering_query(self):
 | 
						def test_preload_triggering_query(self):
 | 
				
			||||||
		''' Make sure that preload issues a disco '''
 | 
							''' Make sure that preload issues a disco '''
 | 
				
			||||||
		connection = Mock()
 | 
							connection = Mock()
 | 
				
			||||||
 | 
							client_caps = ClientCaps(self.caps_hash, self.node, self.caps_method)
 | 
				
			||||||
				
 | 
									
 | 
				
			||||||
		self.cc.preload(connection, "test@gajim.org", self.node,
 | 
							self.cc.query_client_of_jid_if_unknown(connection, "test@gajim.org",
 | 
				
			||||||
				self.caps_method, self.caps_hash)
 | 
									client_caps)
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		connection.mockCheckCall(0, "discoverInfo", "test@gajim.org", 
 | 
							self.assertEqual(1, len(connection.mockGetAllCalls()))
 | 
				
			||||||
				"http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=")
 | 
					 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
	def test_no_preload_query_if_cashed(self):
 | 
						def test_no_preload_query_if_cashed(self):
 | 
				
			||||||
		''' Preload must not send a query if the data is already cached '''
 | 
							''' Preload must not send a query if the data is already cached '''
 | 
				
			||||||
		connection = Mock()
 | 
							connection = Mock()
 | 
				
			||||||
 | 
							client_caps = ClientCaps(self.caps_hash, self.node, self.caps_method)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		self.cc.initialize_from_db()
 | 
							self.cc.initialize_from_db()
 | 
				
			||||||
		self.cc.preload(connection, "test@gajim.org", self.node,
 | 
							self.cc.query_client_of_jid_if_unknown(connection, "test@gajim.org",
 | 
				
			||||||
				self.caps_method, self.caps_hash)
 | 
									client_caps)
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
		self.assertEqual(0, len(connection.mockGetAllCalls()))
 | 
							self.assertEqual(0, len(connection.mockGetAllCalls()))
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
	def test_is_supported(self):
 | 
					 | 
				
			||||||
		contact = Contact(caps_node=self.node,
 | 
					 | 
				
			||||||
								caps_hash_method=self.caps_method,
 | 
					 | 
				
			||||||
								caps_hash=self.caps_hash)
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		self.assertTrue(self.cc.is_supported(contact, NS_PING),
 | 
					 | 
				
			||||||
				msg="Assume everything is supported, if we don't have caps")
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		self.cc.initialize_from_db()
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		self.assertFalse(self.cc.is_supported(contact, NS_PING),
 | 
					 | 
				
			||||||
				msg="Must return false on unsupported feature")
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		self.assertTrue(self.cc.is_supported(contact, NS_MUC),
 | 
					 | 
				
			||||||
				msg="Must return True on supported feature")
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
	def test_hash(self):
 | 
						def test_hash(self):
 | 
				
			||||||
		'''tests the hash computation'''
 | 
							'''tests the hash computation'''
 | 
				
			||||||
		computed_hash = helpers.compute_caps_hash(self.identities, self.features)
 | 
							computed_hash = helpers.compute_caps_hash(self.identities, self.features)
 | 
				
			||||||
| 
						 | 
					@ -117,41 +106,36 @@ class TestClientCaps(CommonCapsTest):
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	def setUp(self):
 | 
						def setUp(self):
 | 
				
			||||||
		CommonCapsTest.setUp(self)
 | 
							CommonCapsTest.setUp(self)
 | 
				
			||||||
		self.caps = ClientCaps(self.cc, self.caps_hash, self.node,
 | 
							self.client_caps = ClientCaps(self.caps_hash, self.node, self.caps_method) 
 | 
				
			||||||
			self.caps_method) 
 | 
					 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
	def test_no_query_client_of_jid(self):
 | 
						def test_query_by_get_discover_strategy(self):
 | 
				
			||||||
		''' Client must not be queried if the data is already cached '''		
 | 
					 | 
				
			||||||
		connection = Mock()
 | 
					 | 
				
			||||||
		self.cc.initialize_from_db()
 | 
					 | 
				
			||||||
		self.caps.query_client_of_jid_if_unknown(connection, "test@gajim.org")
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		self.assertEqual(0, len(connection.mockGetAllCalls()))
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	def test_query_client_of_jid_if_unknown(self):
 | 
					 | 
				
			||||||
		''' Client must be queried if the data is unkown '''	
 | 
							''' Client must be queried if the data is unkown '''	
 | 
				
			||||||
		connection = Mock()
 | 
							connection = Mock()
 | 
				
			||||||
		self.caps.query_client_of_jid_if_unknown(connection, "test@gajim.org")	
 | 
							discover = self.client_caps.get_discover_strategy()
 | 
				
			||||||
 | 
							discover(connection, "test@gajim.org")	
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		connection.mockCheckCall(0, "discoverInfo", "test@gajim.org", 
 | 
							connection.mockCheckCall(0, "discoverInfo", "test@gajim.org", 
 | 
				
			||||||
				"http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=")
 | 
									"http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=")
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
	def test_is_supported(self):		
 | 
						def test_client_supports(self):
 | 
				
			||||||
		self.assertTrue(self.caps.contains_feature(NS_PING),
 | 
							contact = Contact(caps_cache=self.cc)
 | 
				
			||||||
 | 
							contact.set_supported_client_caps(self.client_caps)
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							self.assertTrue(contact.supports(NS_PING),
 | 
				
			||||||
				msg="Assume supported, if we don't have caps")
 | 
									msg="Assume supported, if we don't have caps")
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		self.assertFalse(self.caps.contains_feature(NS_XHTML_IM),
 | 
							self.assertFalse(contact.supports(NS_XHTML_IM),
 | 
				
			||||||
			msg="Must not assume blacklisted feature is supported on default")
 | 
								msg="Must not assume blacklisted feature is supported on default")
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		self.cc.initialize_from_db()
 | 
							self.cc.initialize_from_db()
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		self.assertFalse(self.caps.contains_feature(NS_PING),
 | 
							self.assertFalse(contact.supports(NS_PING),
 | 
				
			||||||
				msg="Must return false on unsupported feature")
 | 
									msg="Must return false on unsupported feature")
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		self.assertTrue(self.caps.contains_feature(NS_XHTML_IM),
 | 
							self.assertTrue(contact.supports(NS_XHTML_IM),
 | 
				
			||||||
				msg="Must return True on supported feature")
 | 
									msg="Must return True on supported feature")
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		self.assertTrue(self.caps.contains_feature(NS_MUC),
 | 
							self.assertTrue(contact.supports(NS_MUC),
 | 
				
			||||||
				msg="Must return True on supported feature")	
 | 
									msg="Must return True on supported feature")	
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -159,25 +143,17 @@ class TestOldClientCaps(TestClientCaps):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def setUp(self):
 | 
						def setUp(self):
 | 
				
			||||||
		TestClientCaps.setUp(self)
 | 
							TestClientCaps.setUp(self)
 | 
				
			||||||
		self.caps = OldClientCaps(self.cc, self.caps_hash, self.node) 
 | 
							self.client_caps = OldClientCaps(self.caps_hash, self.node) 
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	def test_no_query_client_of_jid(self):
 | 
						def test_query_by_get_discover_strategy(self):
 | 
				
			||||||
		''' Client must not be queried if the data is already cached '''		
 | 
							''' Client must be queried if the data is unknown '''	
 | 
				
			||||||
		connection = Mock()
 | 
							connection = Mock()
 | 
				
			||||||
		self.cc.initialize_from_db()
 | 
							discover = self.client_caps.get_discover_strategy()
 | 
				
			||||||
		self.caps.query_client_of_jid_if_unknown(connection, "test@gajim.org")
 | 
							discover(connection, "test@gajim.org")	
 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		self.assertEqual(0, len(connection.mockGetAllCalls()))
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	def test_query_client_of_jid_if_unknown(self):
 | 
					 | 
				
			||||||
		''' Client must be queried if the data is unkown '''	
 | 
					 | 
				
			||||||
		connection = Mock()
 | 
					 | 
				
			||||||
		self.caps.query_client_of_jid_if_unknown(connection, "test@gajim.org")	
 | 
					 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		connection.mockCheckCall(0, "discoverInfo", "test@gajim.org")
 | 
							connection.mockCheckCall(0, "discoverInfo", "test@gajim.org")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
	unittest.main()
 | 
						unittest.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,36 +6,43 @@ import unittest
 | 
				
			||||||
import lib
 | 
					import lib
 | 
				
			||||||
lib.setup_env()
 | 
					lib.setup_env()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from common.contacts import Contact
 | 
					from common.contacts import Contact, GC_Contact
 | 
				
			||||||
from common.caps import NullClientCaps
 | 
					from common.caps import NullClientCaps
 | 
				
			||||||
 | 
					from common.xmpp import NS_MUC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from mock import Mock
 | 
					class TestCommonContact(unittest.TestCase):
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
class TestContact(unittest.TestCase):
 | 
						def setUp(self):
 | 
				
			||||||
 | 
							self.contact = Contact()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		def test_supports(self):
 | 
						def test_default_client_supports(self):
 | 
				
			||||||
			''' Test the Entity Capabilities part of the contact instance '''
 | 
							'''
 | 
				
			||||||
 | 
							Test the caps support method of contacts.
 | 
				
			||||||
 | 
							See test_caps for more enhanced tests.
 | 
				
			||||||
 | 
							'''
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
			NS_MUC = 'http://jabber.org/protocol/muc'
 | 
							self.assertTrue(self.contact.supports(NS_MUC),
 | 
				
			||||||
 | 
								msg="Must not backtrace on simple check for supported feature")
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
			# Test with mocks to get basic set/get property behaviour checked
 | 
							client_caps = NullClientCaps()
 | 
				
			||||||
			all_supported_mock_entity_caps = Mock(
 | 
							self.contact.set_supported_client_caps(client_caps)
 | 
				
			||||||
						returnValues={"contains_feature": True})
 | 
					 | 
				
			||||||
			nothing_supported_mock_entity_caps = Mock(
 | 
					 | 
				
			||||||
						returnValues={"contains_feature": False})
 | 
					 | 
				
			||||||
					
 | 
										
 | 
				
			||||||
			contact = Contact()
 | 
							self.assertTrue(self.contact.supports(NS_MUC),
 | 
				
			||||||
 | 
								msg="Must not backtrace on simple check for supported feature")
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
			contact.supports = all_supported_mock_entity_caps			
 | 
					 | 
				
			||||||
			self.assertTrue(contact.supports(NS_MUC))
 | 
					 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			contact.supports = nothing_supported_mock_entity_caps
 | 
					class TestContact(TestCommonContact):
 | 
				
			||||||
			self.assertFalse(contact.supports(NS_MUC))
 | 
					 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
			# Test with EntityCapabilites to detect API changes
 | 
						def setUp(self):
 | 
				
			||||||
			contact.supports = NullClientCaps()
 | 
							TestCommonContact.setUp(self)
 | 
				
			||||||
			self.assertTrue(contact.supports(NS_MUC),
 | 
							self.contact = Contact()
 | 
				
			||||||
				msg="Default behaviour is to support everything on unknown caps")
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestGC_Contact(TestCommonContact):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def setUp(self):
 | 
				
			||||||
 | 
							TestCommonContact.setUp(self)
 | 
				
			||||||
 | 
							self.contact = GC_Contact()
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue