Split common/caps.py. We now have common/protocol/ to contain XMPP connection related classes.
Plan is to move our ConnectionX classess to the protocol package one by one. Each move should be more than a simple copy paste. It should be preceeded by cleanups and the like.
This commit is contained in:
parent
7708e3b87e
commit
e9caf06992
|
@ -1,5 +1,5 @@
|
|||
# -*- coding:utf-8 -*-
|
||||
## src/common/caps.py
|
||||
## src/common/caps_cache.py
|
||||
##
|
||||
## Copyright (C) 2007 Tomasz Melcer <liori AT exroot.org>
|
||||
## Travis Shirk <travis AT pobox.com>
|
||||
|
@ -31,13 +31,11 @@ CapsCache caches features to hash relationships. The cache is queried
|
|||
through ClientCaps objects which are hold by contact instances.
|
||||
"""
|
||||
|
||||
import gajim
|
||||
import helpers
|
||||
import base64
|
||||
import hashlib
|
||||
|
||||
import logging
|
||||
log = logging.getLogger('gajim.c.caps')
|
||||
log = logging.getLogger('gajim.c.caps_cache')
|
||||
|
||||
from common.xmpp import (NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION, NS_CHATSTATES,
|
||||
NS_JINGLE_ICE_UDP, NS_JINGLE_RTP_AUDIO, NS_JINGLE_RTP_VIDEO, NS_CAPS)
|
||||
|
@ -76,6 +74,20 @@ def client_supports(client_caps, requested_feature):
|
|||
else:
|
||||
return False
|
||||
|
||||
def create_suitable_client_caps(node, caps_hash, hash_method):
|
||||
"""
|
||||
Create and return a suitable ClientCaps object for the given node,
|
||||
caps_hash, hash_method combination.
|
||||
"""
|
||||
if not node or not caps_hash:
|
||||
# improper caps, ignore client capabilities.
|
||||
client_caps = NullClientCaps()
|
||||
elif not hash_method:
|
||||
client_caps = OldClientCaps(caps_hash, node)
|
||||
else:
|
||||
client_caps = ClientCaps(caps_hash, node, hash_method)
|
||||
return client_caps
|
||||
|
||||
def compute_caps_hash(identities, features, dataforms=[], hash_method='sha-1'):
|
||||
"""
|
||||
Compute caps hash according to XEP-0115, V1.5
|
||||
|
@ -151,22 +163,6 @@ def compute_caps_hash(identities, features, dataforms=[], hash_method='sha-1'):
|
|||
### Internal classes of this module
|
||||
################################################################################
|
||||
|
||||
|
||||
def create_suitable_client_caps(node, caps_hash, hash_method):
|
||||
"""
|
||||
Create and return a suitable ClientCaps object for the given node,
|
||||
caps_hash, hash_method combination.
|
||||
"""
|
||||
if not node or not caps_hash:
|
||||
# improper caps, ignore client capabilities.
|
||||
client_caps = NullClientCaps()
|
||||
elif not hash_method:
|
||||
client_caps = OldClientCaps(caps_hash, node)
|
||||
else:
|
||||
client_caps = ClientCaps(caps_hash, node, hash_method)
|
||||
return client_caps
|
||||
|
||||
|
||||
class AbstractClientCaps(object):
|
||||
"""
|
||||
Base class representing a client and its capabilities as advertised by a
|
||||
|
@ -208,7 +204,6 @@ class ClientCaps(AbstractClientCaps):
|
|||
"""
|
||||
The current XEP-115 implementation
|
||||
"""
|
||||
|
||||
def __init__(self, caps_hash, node, hash_method):
|
||||
AbstractClientCaps.__init__(self, caps_hash, node)
|
||||
assert hash_method != 'old'
|
||||
|
@ -230,7 +225,6 @@ class OldClientCaps(AbstractClientCaps):
|
|||
"""
|
||||
Old XEP-115 implemtation. Kept around for background competability
|
||||
"""
|
||||
|
||||
def __init__(self, caps_hash, node):
|
||||
AbstractClientCaps.__init__(self, caps_hash, node)
|
||||
|
||||
|
@ -251,7 +245,6 @@ class NullClientCaps(AbstractClientCaps):
|
|||
|
||||
Assumes (almost) everything is supported.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
AbstractClientCaps.__init__(self, None, None)
|
||||
|
||||
|
@ -273,7 +266,6 @@ class CapsCache(object):
|
|||
This object keeps the mapping between caps data and real disco features they
|
||||
represent, and provides simple way to query that info
|
||||
"""
|
||||
|
||||
def __init__(self, logger=None):
|
||||
# our containers:
|
||||
# __cache is a dictionary mapping: pair of hash method and hash maps
|
||||
|
@ -346,6 +338,13 @@ class CapsCache(object):
|
|||
self._recently_seen = True
|
||||
self._logger.update_caps_time(self.hash_method, self.hash)
|
||||
|
||||
def is_valid(self):
|
||||
"""
|
||||
Returns True if identities and features for this cache item
|
||||
are known.
|
||||
"""
|
||||
return self.status == CACHED
|
||||
|
||||
self.__CacheItem = CacheItem
|
||||
self.logger = logger
|
||||
|
||||
|
@ -391,80 +390,4 @@ class CapsCache(object):
|
|||
else:
|
||||
q.update_last_seen()
|
||||
|
||||
################################################################################
|
||||
### Caps network coding
|
||||
################################################################################
|
||||
|
||||
class ConnectionCaps(object):
|
||||
|
||||
def __init__(self, account, dispatch_event):
|
||||
self._account = account
|
||||
self._dispatch_event = dispatch_event
|
||||
|
||||
def _capsPresenceCB(self, con, presence):
|
||||
"""
|
||||
XMMPPY callback method to handle retrieved caps info
|
||||
"""
|
||||
try:
|
||||
jid = helpers.get_full_jid_from_iq(presence)
|
||||
except:
|
||||
log.info("Ignoring invalid JID in caps presenceCB")
|
||||
return
|
||||
|
||||
client_caps = self._extract_client_caps_from_presence(presence)
|
||||
capscache.query_client_of_jid_if_unknown(self, jid, client_caps)
|
||||
self._update_client_caps_of_contact(jid, client_caps)
|
||||
|
||||
self._dispatch_event('CAPS_RECEIVED', (jid,))
|
||||
|
||||
def _extract_client_caps_from_presence(self, presence):
|
||||
caps_tag = presence.getTag('c', namespace=NS_CAPS)
|
||||
if caps_tag:
|
||||
hash_method, node, caps_hash = caps_tag['hash'], caps_tag['node'], caps_tag['ver']
|
||||
else:
|
||||
hash_method = node = caps_hash = None
|
||||
return create_suitable_client_caps(node, caps_hash, hash_method)
|
||||
|
||||
def _update_client_caps_of_contact(self, jid, client_caps):
|
||||
contact = self._get_contact_or_gc_contact_for_jid(jid)
|
||||
if contact:
|
||||
contact.client_caps = client_caps
|
||||
else:
|
||||
log.info("Received Caps from unknown contact %s" % jid)
|
||||
|
||||
def _get_contact_or_gc_contact_for_jid(self, jid):
|
||||
contact = gajim.contacts.get_contact_from_full_jid(self._account, jid)
|
||||
if contact is None:
|
||||
room_jid, nick = gajim.get_room_and_nick_from_fjid(jid)
|
||||
contact = gajim.contacts.get_gc_contact(self._account, room_jid, nick)
|
||||
return contact
|
||||
|
||||
def _capsDiscoCB(self, jid, node, identities, features, dataforms):
|
||||
"""
|
||||
XMMPPY callback to update our caps cache with queried information after
|
||||
we have retrieved an unknown caps hash and issued a disco
|
||||
"""
|
||||
contact = self._get_contact_or_gc_contact_for_jid(jid)
|
||||
if not contact:
|
||||
log.info("Received Disco from unknown contact %s" % jid)
|
||||
return
|
||||
|
||||
lookup = contact.client_caps.get_cache_lookup_strategy()
|
||||
cache_item = lookup(capscache)
|
||||
|
||||
if cache_item.status == CACHED:
|
||||
return
|
||||
else:
|
||||
validate = contact.client_caps.get_hash_validation_strategy()
|
||||
hash_is_valid = validate(identities, features, dataforms)
|
||||
|
||||
if hash_is_valid:
|
||||
cache_item.set_and_store(identities, features)
|
||||
else:
|
||||
contact.client_caps = NullClientCaps()
|
||||
log.warn("Computed and retrieved caps hash differ." +
|
||||
"Ignoring caps of contact %s" % contact.get_full_jid())
|
||||
|
||||
self._dispatch_event('CAPS_RECEIVED', (jid,))
|
||||
|
||||
# vim: se ts=3:
|
|
@ -50,7 +50,8 @@ from common import exceptions
|
|||
from common.commands import ConnectionCommands
|
||||
from common.pubsub import ConnectionPubSub
|
||||
from common.pep import ConnectionPEP
|
||||
from common.caps import ConnectionCaps
|
||||
from common.protocol.caps import ConnectionCaps
|
||||
import common.caps_cache as capscache
|
||||
if gajim.HAVE_FARSIGHT:
|
||||
from common.jingle import ConnectionJingle
|
||||
else:
|
||||
|
@ -1520,7 +1521,8 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream,
|
|||
ConnectionPEP.__init__(self, account=self.name, dispatcher=self,
|
||||
pubsub_connection=self)
|
||||
ConnectionCaps.__init__(self, account=self.name,
|
||||
dispatch_event=self.dispatch)
|
||||
dispatch_event=self.dispatch, capscache=capscache.capscache,
|
||||
client_caps_factory=capscache.create_suitable_client_caps)
|
||||
ConnectionJingle.__init__(self)
|
||||
ConnectionHandlersBase.__init__(self)
|
||||
self.gmail_url = None
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
##
|
||||
|
||||
|
||||
from common import caps
|
||||
from common import caps_cache
|
||||
from common.account import Account
|
||||
import common.gajim
|
||||
|
||||
|
@ -54,7 +54,7 @@ class CommonContact(XMPPEntity):
|
|||
self.status = status
|
||||
self.name = name
|
||||
|
||||
self.client_caps = client_caps or caps.NullClientCaps()
|
||||
self.client_caps = client_caps or caps_cache.NullClientCaps()
|
||||
|
||||
# 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:
|
||||
|
@ -89,7 +89,7 @@ class CommonContact(XMPPEntity):
|
|||
# return caps for a contact that has no resources left.
|
||||
return False
|
||||
else:
|
||||
return caps.client_supports(self.client_caps, requested_feature)
|
||||
return caps_cache.client_supports(self.client_caps, requested_feature)
|
||||
|
||||
|
||||
class Contact(CommonContact):
|
||||
|
|
|
@ -211,8 +211,8 @@ gajim_optional_features = {}
|
|||
# Capabilities hash per account
|
||||
caps_hash = {}
|
||||
|
||||
import caps
|
||||
caps.initialize(logger)
|
||||
import caps_cache
|
||||
caps_cache.initialize(logger)
|
||||
|
||||
def get_nick_from_jid(jid):
|
||||
pos = jid.find('@')
|
||||
|
|
|
@ -38,7 +38,7 @@ import errno
|
|||
import select
|
||||
import base64
|
||||
import hashlib
|
||||
import caps
|
||||
import caps_cache
|
||||
|
||||
from encodings.punycode import punycode_encode
|
||||
|
||||
|
@ -1309,7 +1309,7 @@ def update_optional_features(account = None):
|
|||
gajim.gajim_optional_features[a].append(xmpp.NS_JINGLE_RTP_AUDIO)
|
||||
gajim.gajim_optional_features[a].append(xmpp.NS_JINGLE_RTP_VIDEO)
|
||||
gajim.gajim_optional_features[a].append(xmpp.NS_JINGLE_ICE_UDP)
|
||||
gajim.caps_hash[a] = caps.compute_caps_hash([gajim.gajim_identity],
|
||||
gajim.caps_hash[a] = caps_cache.compute_caps_hash([gajim.gajim_identity],
|
||||
gajim.gajim_common_features + gajim.gajim_optional_features[a])
|
||||
# re-send presence with new hash
|
||||
connected = gajim.connections[a].connected
|
||||
|
|
|
@ -32,7 +32,7 @@ import re
|
|||
from time import time
|
||||
from common import gajim
|
||||
from common import helpers
|
||||
from common import caps
|
||||
from common import caps_cache
|
||||
|
||||
import sqlite3 as sqlite
|
||||
import logger
|
||||
|
@ -218,7 +218,7 @@ class OptionsParser:
|
|||
gajim.logger.init_vars()
|
||||
gajim.config.set('version', new_version)
|
||||
|
||||
caps.capscache.initialize_from_db()
|
||||
caps_cache.capscache.initialize_from_db()
|
||||
|
||||
def assert_unread_msgs_table_exists(self):
|
||||
"""
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
Implementations of specific XMPP protocols and XEPs
|
||||
"""
|
|
@ -0,0 +1,110 @@
|
|||
# -*- coding:utf-8 -*-
|
||||
## src/common/protocol/caps.py
|
||||
##
|
||||
## Copyright (C) 2009 Stephan Erb <steve-e AT h3c.de>
|
||||
##
|
||||
## This file is part of Gajim.
|
||||
##
|
||||
## Gajim is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published
|
||||
## by the Free Software Foundation; version 3 only.
|
||||
##
|
||||
## Gajim is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
##
|
||||
|
||||
"""
|
||||
Module containing the network portion of XEP-115 (Entity Capabilities)
|
||||
"""
|
||||
|
||||
import logging
|
||||
log = logging.getLogger('gajim.c.p.caps')
|
||||
|
||||
from common.xmpp import NS_CAPS
|
||||
from common import gajim
|
||||
from common import helpers
|
||||
|
||||
|
||||
class ConnectionCaps(object):
|
||||
|
||||
def __init__(self, account, dispatch_event, capscache, client_caps_factory):
|
||||
self._account = account
|
||||
self._dispatch_event = dispatch_event
|
||||
self._capscache = capscache
|
||||
self._create_suitable_client_caps = client_caps_factory
|
||||
|
||||
def _capsPresenceCB(self, con, presence):
|
||||
"""
|
||||
XMMPPY callback method to handle retrieved caps info
|
||||
"""
|
||||
try:
|
||||
jid = helpers.get_full_jid_from_iq(presence)
|
||||
except:
|
||||
log.info("Ignoring invalid JID in caps presenceCB")
|
||||
return
|
||||
|
||||
client_caps = self._extract_client_caps_from_presence(presence)
|
||||
self._capscache.query_client_of_jid_if_unknown(self, jid, client_caps)
|
||||
self._update_client_caps_of_contact(jid, client_caps)
|
||||
|
||||
self._dispatch_event('CAPS_RECEIVED', (jid,))
|
||||
|
||||
def _extract_client_caps_from_presence(self, presence):
|
||||
caps_tag = presence.getTag('c', namespace=NS_CAPS)
|
||||
if caps_tag:
|
||||
hash_method, node, caps_hash = caps_tag['hash'], caps_tag['node'], caps_tag['ver']
|
||||
else:
|
||||
hash_method = node = caps_hash = None
|
||||
return self._create_suitable_client_caps(node, caps_hash, hash_method)
|
||||
|
||||
def _update_client_caps_of_contact(self, jid, client_caps):
|
||||
contact = self._get_contact_or_gc_contact_for_jid(jid)
|
||||
if contact:
|
||||
contact.client_caps = client_caps
|
||||
else:
|
||||
log.info("Received Caps from unknown contact %s" % jid)
|
||||
|
||||
def _get_contact_or_gc_contact_for_jid(self, jid):
|
||||
contact = gajim.contacts.get_contact_from_full_jid(self._account, jid)
|
||||
if contact is None:
|
||||
room_jid, nick = gajim.get_room_and_nick_from_fjid(jid)
|
||||
contact = gajim.contacts.get_gc_contact(self._account, room_jid, nick)
|
||||
return contact
|
||||
|
||||
def _capsDiscoCB(self, jid, node, identities, features, dataforms):
|
||||
"""
|
||||
XMMPPY callback to update our caps cache with queried information after
|
||||
we have retrieved an unknown caps hash and issued a disco
|
||||
"""
|
||||
contact = self._get_contact_or_gc_contact_for_jid(jid)
|
||||
if not contact:
|
||||
log.info("Received Disco from unknown contact %s" % jid)
|
||||
return
|
||||
|
||||
lookup = contact.client_caps.get_cache_lookup_strategy()
|
||||
cache_item = lookup(self._capscache)
|
||||
|
||||
if cache_item.is_valid():
|
||||
return
|
||||
else:
|
||||
validate = contact.client_caps.get_hash_validation_strategy()
|
||||
hash_is_valid = validate(identities, features, dataforms)
|
||||
|
||||
if hash_is_valid:
|
||||
cache_item.set_and_store(identities, features)
|
||||
else:
|
||||
node = caps_hash = hash_method = None
|
||||
contact.client_caps = self._create_suitable_client_caps(node,
|
||||
caps_hash, hash_method)
|
||||
log.warn("Computed and retrieved caps hash differ." +
|
||||
"Ignoring caps of contact %s" % contact.get_full_jid())
|
||||
|
||||
self._dispatch_event('CAPS_RECEIVED', (jid,))
|
||||
|
||||
|
||||
# vim: se ts=3:
|
|
@ -71,7 +71,7 @@ import common.sleepy
|
|||
from common.xmpp import idlequeue
|
||||
from common.zeroconf import connection_zeroconf
|
||||
from common import resolver
|
||||
from common import caps
|
||||
from common import caps_cache
|
||||
from common import proxy65_manager
|
||||
from common import socks5
|
||||
from common import helpers
|
||||
|
@ -3307,7 +3307,7 @@ class Interface:
|
|||
helpers.update_optional_features()
|
||||
# prepopulate data which we are sure of; note: we do not log these info
|
||||
for account in gajim.connections:
|
||||
gajimcaps = caps.capscache[('sha-1', gajim.caps_hash[account])]
|
||||
gajimcaps = caps_cache.capscache[('sha-1', gajim.caps_hash[account])]
|
||||
gajimcaps.identities = [gajim.gajim_identity]
|
||||
gajimcaps.features = gajim.gajim_common_features + \
|
||||
gajim.gajim_optional_features[account]
|
||||
|
|
|
@ -37,7 +37,8 @@ for o, a in opts:
|
|||
# new test modules need to be added manually
|
||||
modules = ( 'unit.test_xmpp_dispatcher_nb',
|
||||
'unit.test_xmpp_transports_nb',
|
||||
'unit.test_caps',
|
||||
'unit.test_protocol_caps',
|
||||
'unit.test_caps_cache',
|
||||
'unit.test_contacts',
|
||||
'unit.test_sessions',
|
||||
'unit.test_account',
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
'''
|
||||
Tests for capabilities and the capabilities cache
|
||||
'''
|
||||
from common.caps import NullClientCaps
|
||||
import unittest
|
||||
|
||||
import lib
|
||||
lib.setup_env()
|
||||
|
||||
from common.xmpp import NS_MUC, NS_PING, NS_XHTML_IM
|
||||
from common import caps
|
||||
from common import caps_cache as caps
|
||||
from common.contacts import Contact
|
||||
|
||||
from mock import Mock
|
||||
|
@ -146,65 +145,6 @@ class TestOldClientCaps(TestClientCaps):
|
|||
|
||||
connection.mockCheckCall(0, "discoverInfo", "test@gajim.org")
|
||||
|
||||
|
||||
from common.xmpp import simplexml
|
||||
from common.xmpp import protocol
|
||||
|
||||
class TestableConnectionCaps(caps.ConnectionCaps):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._mocked_contacts = {}
|
||||
caps.ConnectionCaps.__init__(self, *args, **kwargs)
|
||||
|
||||
def _get_contact_or_gc_contact_for_jid(self, jid):
|
||||
"""
|
||||
Overwrite to decouple form contact handling
|
||||
"""
|
||||
if jid not in self._mocked_contacts:
|
||||
self._mocked_contacts[jid] = Mock(realClass=Contact)
|
||||
self._mocked_contacts[jid].jid = jid
|
||||
return self._mocked_contacts[jid]
|
||||
|
||||
def discoverInfo(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def get_mocked_contact_for_jid(self, jid):
|
||||
return self._mocked_contacts[jid]
|
||||
|
||||
|
||||
class TestConnectionCaps(CommonCapsTest):
|
||||
|
||||
def test_capsPresenceCB(self):
|
||||
jid = "user@server.com/a"
|
||||
connection_caps = TestableConnectionCaps("account",
|
||||
self._build_assertering_dispatcher_function("CAPS_RECEIVED", jid))
|
||||
|
||||
xml = """<presence from='user@server.com/a'
|
||||
to='%s' id='123'>
|
||||
<c node='http://gajim.org' ver='pRCD6cgQ4SDqNMCjdhRV6TECx5o='
|
||||
hash='sha-1' xmlns='http://jabber.org/protocol/caps'/>
|
||||
</presence>
|
||||
""" % (jid)
|
||||
iq = protocol.Iq(node=simplexml.XML2Node(xml))
|
||||
connection_caps._capsPresenceCB(None, iq)
|
||||
|
||||
self.assertTrue(self._dispatcher_called, msg="Must have received caps")
|
||||
|
||||
client_caps = connection_caps.get_mocked_contact_for_jid(jid).client_caps
|
||||
self.assertTrue(client_caps, msg="Client caps must be set")
|
||||
self.assertFalse(isinstance(client_caps, NullClientCaps),
|
||||
msg="On receive of proper caps, we must not use the fallback")
|
||||
|
||||
def _build_assertering_dispatcher_function(self, expected_event, jid):
|
||||
self._dispatcher_called = False
|
||||
def dispatch(event, data):
|
||||
self.assertFalse(self._dispatcher_called, msg="Must only be called once")
|
||||
self._dispatcher_called = True
|
||||
self.assertEqual(expected_event, event)
|
||||
self.assertEqual(jid, data[0])
|
||||
return dispatch
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -9,7 +9,7 @@ lib.setup_env()
|
|||
from common.contacts import CommonContact, Contact, GC_Contact, LegacyContactsAPI
|
||||
from common.xmpp import NS_MUC
|
||||
|
||||
from common import caps
|
||||
from common import caps_cache
|
||||
|
||||
class TestCommonContact(unittest.TestCase):
|
||||
|
||||
|
@ -23,11 +23,11 @@ class TestCommonContact(unittest.TestCase):
|
|||
Test the caps support method of contacts.
|
||||
See test_caps for more enhanced tests.
|
||||
'''
|
||||
caps.capscache = caps.CapsCache()
|
||||
caps_cache.capscache = caps_cache.CapsCache()
|
||||
self.assertTrue(self.contact.supports(NS_MUC),
|
||||
msg="Must not backtrace on simple check for supported feature")
|
||||
|
||||
self.contact.client_caps = caps.NullClientCaps()
|
||||
self.contact.client_caps = caps_cache.NullClientCaps()
|
||||
|
||||
self.assertTrue(self.contact.supports(NS_MUC),
|
||||
msg="Must not backtrace on simple check for supported feature")
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
'''
|
||||
Tests for caps network coding
|
||||
'''
|
||||
import unittest
|
||||
|
||||
import lib
|
||||
lib.setup_env()
|
||||
|
||||
from common import caps_cache
|
||||
from common.protocol import caps
|
||||
from common.contacts import Contact
|
||||
|
||||
from mock import Mock
|
||||
|
||||
from common.xmpp import simplexml
|
||||
from common.xmpp import protocol
|
||||
|
||||
class TestableConnectionCaps(caps.ConnectionCaps):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._mocked_contacts = {}
|
||||
caps.ConnectionCaps.__init__(self, *args, **kwargs)
|
||||
|
||||
def _get_contact_or_gc_contact_for_jid(self, jid):
|
||||
"""
|
||||
Overwrite to decouple form contact handling
|
||||
"""
|
||||
if jid not in self._mocked_contacts:
|
||||
self._mocked_contacts[jid] = Mock(realClass=Contact)
|
||||
self._mocked_contacts[jid].jid = jid
|
||||
return self._mocked_contacts[jid]
|
||||
|
||||
def discoverInfo(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def get_mocked_contact_for_jid(self, jid):
|
||||
return self._mocked_contacts[jid]
|
||||
|
||||
|
||||
class TestConnectionCaps(unittest.TestCase):
|
||||
|
||||
def test_capsPresenceCB(self):
|
||||
jid = "user@server.com/a"
|
||||
connection_caps = TestableConnectionCaps("account",
|
||||
self._build_assertering_dispatcher_function("CAPS_RECEIVED", jid),
|
||||
Mock(), caps_cache.create_suitable_client_caps)
|
||||
|
||||
xml = """<presence from='user@server.com/a' to='%s' id='123'>
|
||||
<c node='http://gajim.org' ver='pRCD6cgQ4SDqNMCjdhRV6TECx5o='
|
||||
hash='sha-1' xmlns='http://jabber.org/protocol/caps'/>
|
||||
</presence>
|
||||
""" % (jid)
|
||||
iq = protocol.Iq(node=simplexml.XML2Node(xml))
|
||||
connection_caps._capsPresenceCB(None, iq)
|
||||
|
||||
self.assertTrue(self._dispatcher_called, msg="Must have received caps")
|
||||
|
||||
client_caps = connection_caps.get_mocked_contact_for_jid(jid).client_caps
|
||||
self.assertTrue(client_caps, msg="Client caps must be set")
|
||||
self.assertFalse(isinstance(client_caps, caps_cache.NullClientCaps),
|
||||
msg="On receive of proper caps, we must not use the fallback")
|
||||
|
||||
def _build_assertering_dispatcher_function(self, expected_event, jid):
|
||||
self._dispatcher_called = False
|
||||
def dispatch(event, data):
|
||||
self.assertFalse(self._dispatcher_called, msg="Must only be called once")
|
||||
self._dispatcher_called = True
|
||||
self.assertEqual(expected_event, event)
|
||||
self.assertEqual(jid, data[0])
|
||||
return dispatch
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
# vim: se ts=3:
|
Loading…
Reference in New Issue