Redistribute responsibility: Let contact instances check if features are supported
This commit is contained in:
parent
3295b08b26
commit
c7ff97703f
|
@ -39,51 +39,30 @@ import gajim
|
|||
import helpers
|
||||
|
||||
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
|
||||
FEATURE_BLACKLIST = [NS_CHATSTATES, NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION]
|
||||
|
||||
|
||||
class AbstractClientCaps(object):
|
||||
'''
|
||||
Base class representing a client and its capabilities as advertised by
|
||||
a caps tag in a presence
|
||||
'''
|
||||
|
||||
def __init__(self, caps_cache, caps_hash, node):
|
||||
self._caps_cache = caps_cache
|
||||
def __init__(self, caps_hash, node):
|
||||
self._hash = caps_hash
|
||||
self._node = node
|
||||
|
||||
def query_client_of_jid_if_unknown(self, connection, jid):
|
||||
'''
|
||||
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 get_discover_strategy(self):
|
||||
return self._discover
|
||||
|
||||
def _discover(self, connection, jid):
|
||||
''' To be implemented by subclassess '''
|
||||
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 '''
|
||||
raise NotImplementedError()
|
||||
|
||||
|
@ -91,13 +70,13 @@ class AbstractClientCaps(object):
|
|||
class ClientCaps(AbstractClientCaps):
|
||||
''' The current XEP-115 implementation '''
|
||||
|
||||
def __init__(self, caps_cache, caps_hash, node, hash_method):
|
||||
AbstractClientCaps.__init__(self, caps_cache, caps_hash, node)
|
||||
def __init__(self, caps_hash, node, hash_method):
|
||||
AbstractClientCaps.__init__(self, caps_hash, node)
|
||||
assert hash_method != 'old'
|
||||
self._hash_method = hash_method
|
||||
|
||||
def _lookup_in_cache(self):
|
||||
return self._caps_cache[(self._hash_method, self._hash)]
|
||||
def _lookup_in_cache(self, caps_cache):
|
||||
return caps_cache[(self._hash_method, self._hash)]
|
||||
|
||||
def _discover(self, connection, jid):
|
||||
connection.discoverInfo(jid, '%s#%s' % (self._node, self._hash))
|
||||
|
@ -106,11 +85,11 @@ class ClientCaps(AbstractClientCaps):
|
|||
class OldClientCaps(AbstractClientCaps):
|
||||
''' Old XEP-115 implemtation. Kept around for background competability. '''
|
||||
|
||||
def __init__(self, caps_cache, caps_hash, node):
|
||||
AbstractClientCaps.__init__(self, caps_cache, caps_hash, node)
|
||||
def __init__(self, caps_hash, node):
|
||||
AbstractClientCaps.__init__(self, caps_hash, node)
|
||||
|
||||
def _lookup_in_cache(self):
|
||||
return self._caps_cache[('old', self._node + '#' + self._hash)]
|
||||
def _lookup_in_cache(self, caps_cache):
|
||||
return caps_cache[('old', self._node + '#' + self._hash)]
|
||||
|
||||
def _discover(self, connection, jid):
|
||||
connection.discoverInfo(jid)
|
||||
|
@ -125,32 +104,19 @@ class NullClientCaps(AbstractClientCaps):
|
|||
'''
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
AbstractClientCaps.__init__(self, None, None)
|
||||
|
||||
def query_client_of_jid_if_unknown(self, connection, jid):
|
||||
pass
|
||||
def _lookup_in_cache(self, caps_cache):
|
||||
return caps_cache[('old', '')]
|
||||
|
||||
def contains_feature(self, feature):
|
||||
return feature not in FEATURE_BLACKLIST
|
||||
def _discover(self, connection, jid):
|
||||
pass
|
||||
|
||||
|
||||
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.
|
||||
|
||||
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):
|
||||
''' Create a cache for entity capabilities. '''
|
||||
|
@ -219,15 +185,14 @@ class CapsCache(object):
|
|||
|
||||
def update(self, identities, features):
|
||||
# NOTE: self refers to CapsCache object, not to CacheItem
|
||||
self.identities=identities
|
||||
self.features=features
|
||||
self.identities = identities
|
||||
self.features = features
|
||||
self._logger.add_caps_entry(self.hash_method, self.hash,
|
||||
identities, features)
|
||||
|
||||
self.__CacheItem = CacheItem
|
||||
|
||||
# prepopulate data which we are sure of; note: we do not log these info
|
||||
|
||||
for account in gajim.connections:
|
||||
gajimcaps = self[('sha-1', gajim.caps_hash[account])]
|
||||
gajimcaps.identities = [gajim.gajim_identity]
|
||||
|
@ -257,48 +222,19 @@ class CapsCache(object):
|
|||
self.__cache[(hash_method, hash_)] = 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
|
||||
query to jid using proper connection. Don't query if
|
||||
the data is already in cache. '''
|
||||
if hash_method == 'old':
|
||||
q = self[(hash_method, node + '#' + hash_)]
|
||||
else:
|
||||
q = self[(hash_method, hash_)]
|
||||
lookup_cache_item = client_caps.get_cache_lookup_strategy()
|
||||
q = lookup_cache_item(self)
|
||||
|
||||
if q.queried==0:
|
||||
if q.queried == 0:
|
||||
# do query for bare node+hash pair
|
||||
# this will create proper object
|
||||
q.queried=1
|
||||
if hash_method == 'old':
|
||||
con.discoverInfo(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
|
||||
q.queried = 1
|
||||
discover = client_caps.get_discover_strategy()
|
||||
discover(connection, jid)
|
||||
|
||||
gajim.capscache = CapsCache(gajim.logger)
|
||||
|
||||
|
|
|
@ -30,12 +30,15 @@
|
|||
|
||||
import common.gajim
|
||||
|
||||
from common.caps import NullClientCaps, FEATURE_BLACKLIST
|
||||
|
||||
|
||||
class Contact(object):
|
||||
'''Information concerning each contact'''
|
||||
def __init__(self, jid='', name='', groups=[], show='', status='', sub='',
|
||||
ask='', resource='', priority=0, keyID='', caps_node=None,
|
||||
caps_hash_method=None, caps_hash=None, our_chatstate=None, chatstate=None,
|
||||
last_status_time=None, msg_id = None, composing_xep = None, mood={}, tune={},
|
||||
ask='', resource='', priority=0, keyID='', client_caps=None, caps_cache=None,
|
||||
our_chatstate=None, chatstate=None, last_status_time=None, msg_id = None,
|
||||
composing_xep = None, mood={}, tune={},
|
||||
activity={}):
|
||||
self.jid = jid
|
||||
self.name = name
|
||||
|
@ -49,11 +52,9 @@ class Contact(object):
|
|||
self.priority = priority
|
||||
self.keyID = keyID
|
||||
|
||||
# Capabilities; filled by caps.py/ConnectionCaps object
|
||||
# every time it gets these from presence stanzas
|
||||
self.caps_node = caps_node
|
||||
self.caps_hash_method = caps_hash_method
|
||||
self.caps_hash = caps_hash
|
||||
# Entity Capabilities
|
||||
self._client_caps = client_caps or NullClientCaps()
|
||||
self._caps_cache = caps_cache or common.gajim.capscache
|
||||
|
||||
# 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:
|
||||
|
@ -135,31 +136,33 @@ class Contact(object):
|
|||
return False
|
||||
|
||||
|
||||
def _set_supported_caps(self, value):
|
||||
'''
|
||||
Set an EntityCapabilities object
|
||||
'''
|
||||
self._caps = value
|
||||
def supports(self, requested_feature):
|
||||
if self.show == 'offline':
|
||||
# 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.
|
||||
return False
|
||||
else:
|
||||
return self._client_supports(requested_feature)
|
||||
|
||||
def _get_supported_caps(self):
|
||||
'''
|
||||
Returns a function which delegates to the EntityCapabilites support checker
|
||||
def _client_supports(self, requested_feature):
|
||||
lookup_item = self._client_caps.get_cache_lookup_strategy()
|
||||
cache_item = lookup_item(self._caps_cache)
|
||||
|
||||
This allows easy checks like:
|
||||
if contact.supports(NS_COOL_FEATURE): ...
|
||||
'''
|
||||
def test(feature):
|
||||
if self.show == 'offline':
|
||||
# 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.
|
||||
return False
|
||||
else:
|
||||
return self._caps.contains_feature(feature)
|
||||
return test
|
||||
supported_features = cache_item.features
|
||||
if requested_feature in supported_features:
|
||||
return True
|
||||
elif supported_features == [] and cache_item.queried in (0, 1):
|
||||
# assume feature is supported, if we don't know yet, what the client
|
||||
# is capable of
|
||||
return requested_feature not in FEATURE_BLACKLIST
|
||||
else:
|
||||
return False
|
||||
|
||||
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:
|
||||
|
@ -175,9 +178,11 @@ class GC_Contact:
|
|||
self.affiliation = affiliation
|
||||
self.jid = jid
|
||||
self.resource = resource
|
||||
self.caps_node = None
|
||||
self.caps_hash_method = None
|
||||
self.caps_hash = None
|
||||
|
||||
# Entity Capabilities
|
||||
self._client_caps = NullClientCaps()
|
||||
self._caps_cache = common.gajim.capscache
|
||||
|
||||
self.our_chatstate = our_chatstate
|
||||
self.composing_xep = composing_xep
|
||||
self.chatstate = chatstate
|
||||
|
@ -188,31 +193,33 @@ class GC_Contact:
|
|||
def get_shown_name(self):
|
||||
return self.name
|
||||
|
||||
def _set_supported_caps(self, value):
|
||||
'''
|
||||
Set an EntityCapabilities object
|
||||
'''
|
||||
self._caps = value
|
||||
def supports(self, requested_feature):
|
||||
if self.show == 'offline':
|
||||
# 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.
|
||||
return False
|
||||
else:
|
||||
return self._client_supports(requested_feature)
|
||||
|
||||
def _get_supported_caps(self):
|
||||
'''
|
||||
Returns a function which delegates to the EntityCapabilites support checker
|
||||
def _client_supports(self, requested_feature):
|
||||
lookup_item = self._client_caps.get_cache_lookup_strategy()
|
||||
cache_item = lookup_item(self._caps_cache)
|
||||
|
||||
This allows easy checks like:
|
||||
if contact.supports(NS_COOL_FEATURE): ...
|
||||
'''
|
||||
def test(feature):
|
||||
if self.show == 'offline':
|
||||
# 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.
|
||||
return False
|
||||
else:
|
||||
return self._caps.contains_feature(feature)
|
||||
return test
|
||||
supported_features = cache_item.features
|
||||
if requested_feature in supported_features:
|
||||
return True
|
||||
elif supported_features == [] and cache_item.queried in (0, 1):
|
||||
# assume feature is supported, if we don't know yet, what the client
|
||||
# is capable of
|
||||
return requested_feature not in FEATURE_BLACKLIST
|
||||
else:
|
||||
return False
|
||||
|
||||
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:
|
||||
'''Information concerning all contacts and groupchat contacts'''
|
||||
|
@ -246,8 +253,8 @@ class Contacts:
|
|||
del self._metacontacts_tags[account]
|
||||
|
||||
def create_contact(self, jid='', name='', groups=[], show='', status='',
|
||||
sub='', ask='', resource='', priority=0, keyID='', caps_node=None,
|
||||
caps_hash_method=None, caps_hash=None, our_chatstate=None,
|
||||
sub='', ask='', resource='', priority=0, keyID='', client_caps=None,
|
||||
caps_cache=None, our_chatstate=None,
|
||||
chatstate=None, last_status_time=None, composing_xep=None,
|
||||
mood={}, tune={}, activity={}):
|
||||
|
||||
|
@ -259,8 +266,8 @@ class Contacts:
|
|||
|
||||
return Contact(jid=jid, name=name, groups=groups_unique, show=show,
|
||||
status=status, sub=sub, ask=ask, resource=resource, priority=priority,
|
||||
keyID=keyID, caps_node=caps_node, caps_hash_method=caps_hash_method,
|
||||
caps_hash=caps_hash, our_chatstate=our_chatstate, chatstate=chatstate,
|
||||
keyID=keyID, client_caps=client_caps, caps_cache=caps_cache,
|
||||
our_chatstate=our_chatstate, chatstate=chatstate,
|
||||
last_status_time=last_status_time, composing_xep=composing_xep,
|
||||
mood=mood, tune=tune, activity=activity)
|
||||
|
||||
|
@ -269,8 +276,8 @@ class Contacts:
|
|||
groups=contact.groups, show=contact.show, status=contact.status,
|
||||
sub=contact.sub, ask=contact.ask, resource=contact.resource,
|
||||
priority=contact.priority, keyID=contact.keyID,
|
||||
caps_node=contact.caps_node, caps_hash_method=contact.caps_hash_method,
|
||||
caps_hash=contact.caps_hash, our_chatstate=contact.our_chatstate,
|
||||
client_caps=contact._client_caps, caps_cache=contact._caps_cache,
|
||||
our_chatstate=contact.our_chatstate,
|
||||
chatstate=contact.chatstate, last_status_time=contact.last_status_time)
|
||||
|
||||
def add_contact(self, account, contact):
|
||||
|
@ -640,9 +647,8 @@ class Contacts:
|
|||
jid = gc_contact.get_full_jid()
|
||||
return Contact(jid=jid, resource=gc_contact.resource,
|
||||
name=gc_contact.name, groups=[], show=gc_contact.show,
|
||||
status=gc_contact.status, sub='none', caps_node=gc_contact.caps_node,
|
||||
caps_hash_method=gc_contact.caps_hash_method,
|
||||
caps_hash=gc_contact.caps_hash)
|
||||
status=gc_contact.status, sub='none', client_caps=gc_contact._client_caps,
|
||||
caps_cache=gc_contact._caps_cache)
|
||||
|
||||
def create_gc_contact(self, room_jid='', name='', show='', status='',
|
||||
role='', affiliation='', jid='', resource=''):
|
||||
|
|
|
@ -32,8 +32,6 @@ import logging
|
|||
import locale
|
||||
|
||||
import config
|
||||
from contacts import Contacts
|
||||
from events import Events
|
||||
import xmpp
|
||||
|
||||
try:
|
||||
|
@ -101,6 +99,9 @@ else:
|
|||
|
||||
os_info = None # used to cache os information
|
||||
|
||||
from contacts import Contacts
|
||||
from events import Events
|
||||
|
||||
gmail_domains = ['gmail.com', 'googlemail.com']
|
||||
|
||||
transport_type = {} # list the type of transport
|
||||
|
|
|
@ -6,11 +6,11 @@ import unittest
|
|||
import lib
|
||||
lib.setup_env()
|
||||
|
||||
from common import gajim
|
||||
from common import helpers
|
||||
from common.contacts import Contact
|
||||
from common.xmpp import NS_MUC, NS_PING, NS_XHTML_IM
|
||||
|
||||
from common.caps import CapsCache, ClientCaps, OldClientCaps
|
||||
from common.contacts import Contact
|
||||
|
||||
from mock import Mock
|
||||
|
||||
|
@ -20,7 +20,7 @@ class CommonCapsTest(unittest.TestCase):
|
|||
def setUp(self):
|
||||
self.caps_method = 'sha-1'
|
||||
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.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.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):
|
||||
|
@ -42,13 +46,13 @@ class TestCapsCache(CommonCapsTest):
|
|||
def test_set_retrieve(self):
|
||||
''' Test basic set / retrieve cycle '''
|
||||
|
||||
self.cc[self.caps].identities = self.identities
|
||||
self.cc[self.caps].features = self.features
|
||||
self.cc[self.client_caps].identities = self.identities
|
||||
self.cc[self.client_caps].features = self.features
|
||||
|
||||
self.assert_(NS_MUC in self.cc[self.caps].features)
|
||||
self.assert_(NS_PING not 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.client_caps].features)
|
||||
|
||||
identities = self.cc[self.caps].identities
|
||||
identities = self.cc[self.client_caps].identities
|
||||
|
||||
self.assertEqual(1, len(identities))
|
||||
|
||||
|
@ -57,9 +61,9 @@ class TestCapsCache(CommonCapsTest):
|
|||
self.assertEqual('pc', identity['type'])
|
||||
|
||||
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)
|
||||
|
||||
self.logger.mockCheckCall(0, "add_caps_entry", self.caps_method,
|
||||
|
@ -67,46 +71,31 @@ class TestCapsCache(CommonCapsTest):
|
|||
|
||||
def test_initialize_from_db(self):
|
||||
''' 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.assertEqual(self.cc[self.caps].queried, 2)
|
||||
self.assertEqual(self.cc[self.client_caps].queried, 2)
|
||||
|
||||
def test_preload_triggering_query(self):
|
||||
''' Make sure that preload issues a disco '''
|
||||
connection = Mock()
|
||||
client_caps = ClientCaps(self.caps_hash, self.node, self.caps_method)
|
||||
|
||||
self.cc.preload(connection, "test@gajim.org", self.node,
|
||||
self.caps_method, self.caps_hash)
|
||||
self.cc.query_client_of_jid_if_unknown(connection, "test@gajim.org",
|
||||
client_caps)
|
||||
|
||||
connection.mockCheckCall(0, "discoverInfo", "test@gajim.org",
|
||||
"http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=")
|
||||
self.assertEqual(1, len(connection.mockGetAllCalls()))
|
||||
|
||||
def test_no_preload_query_if_cashed(self):
|
||||
''' Preload must not send a query if the data is already cached '''
|
||||
connection = Mock()
|
||||
client_caps = ClientCaps(self.caps_hash, self.node, self.caps_method)
|
||||
|
||||
self.cc.initialize_from_db()
|
||||
self.cc.preload(connection, "test@gajim.org", self.node,
|
||||
self.caps_method, self.caps_hash)
|
||||
self.cc.query_client_of_jid_if_unknown(connection, "test@gajim.org",
|
||||
client_caps)
|
||||
|
||||
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):
|
||||
'''tests the hash computation'''
|
||||
computed_hash = helpers.compute_caps_hash(self.identities, self.features)
|
||||
|
@ -117,41 +106,36 @@ class TestClientCaps(CommonCapsTest):
|
|||
|
||||
def setUp(self):
|
||||
CommonCapsTest.setUp(self)
|
||||
self.caps = ClientCaps(self.cc, self.caps_hash, self.node,
|
||||
self.caps_method)
|
||||
self.client_caps = ClientCaps(self.caps_hash, self.node, self.caps_method)
|
||||
|
||||
def test_no_query_client_of_jid(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):
|
||||
def test_query_by_get_discover_strategy(self):
|
||||
''' Client must be queried if the data is unkown '''
|
||||
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",
|
||||
"http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=")
|
||||
|
||||
def test_is_supported(self):
|
||||
self.assertTrue(self.caps.contains_feature(NS_PING),
|
||||
def test_client_supports(self):
|
||||
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")
|
||||
|
||||
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")
|
||||
|
||||
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")
|
||||
|
||||
self.assertTrue(self.caps.contains_feature(NS_XHTML_IM),
|
||||
self.assertTrue(contact.supports(NS_XHTML_IM),
|
||||
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")
|
||||
|
||||
|
||||
|
@ -159,25 +143,17 @@ class TestOldClientCaps(TestClientCaps):
|
|||
|
||||
def 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):
|
||||
''' Client must not be queried if the data is already cached '''
|
||||
def test_query_by_get_discover_strategy(self):
|
||||
''' Client must be queried if the data is unknown '''
|
||||
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 '''
|
||||
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")
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
|
|
|
@ -6,36 +6,43 @@ import unittest
|
|||
import lib
|
||||
lib.setup_env()
|
||||
|
||||
from common.contacts import Contact
|
||||
from common.contacts import Contact, GC_Contact
|
||||
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):
|
||||
''' Test the Entity Capabilities part of the contact instance '''
|
||||
def test_default_client_supports(self):
|
||||
'''
|
||||
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
|
||||
all_supported_mock_entity_caps = Mock(
|
||||
returnValues={"contains_feature": True})
|
||||
nothing_supported_mock_entity_caps = Mock(
|
||||
returnValues={"contains_feature": False})
|
||||
client_caps = NullClientCaps()
|
||||
self.contact.set_supported_client_caps(client_caps)
|
||||
|
||||
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
|
||||
self.assertFalse(contact.supports(NS_MUC))
|
||||
class TestContact(TestCommonContact):
|
||||
|
||||
# Test with EntityCapabilites to detect API changes
|
||||
contact.supports = NullClientCaps()
|
||||
self.assertTrue(contact.supports(NS_MUC),
|
||||
msg="Default behaviour is to support everything on unknown caps")
|
||||
def setUp(self):
|
||||
TestCommonContact.setUp(self)
|
||||
self.contact = Contact()
|
||||
|
||||
|
||||
class TestGC_Contact(TestCommonContact):
|
||||
|
||||
def setUp(self):
|
||||
TestCommonContact.setUp(self)
|
||||
self.contact = GC_Contact()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
Loading…
Reference in New Issue