Improve common/caps.py test coverage.
This commit is contained in:
parent
2ca65bf6da
commit
0440aec980
|
@ -29,45 +29,20 @@ import helpers
|
||||||
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
|
It is application-wide, that is there's one object for all
|
||||||
connections.
|
connections.
|
||||||
|
|
||||||
Goals:
|
Goals:
|
||||||
* handle storing/retrieving info from database
|
* handle storing/retrieving info from database
|
||||||
* cache info in memory
|
* cache info in memory
|
||||||
* expose simple interface
|
* expose simple interface
|
||||||
|
|
||||||
Properties:
|
Properties:
|
||||||
* one object for all connections (move to logger.py?)
|
* one object for all connections (move to logger.py?)
|
||||||
* store info efficiently (a set() of urls -- we can assume there won't be
|
* 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
|
too much of these, ensure that (X,Y,Z1) and (X,Y,Z2) has different
|
||||||
features.
|
features.
|
||||||
|
|
||||||
Connections with other objects: (TODO)
|
|
||||||
|
|
||||||
Interface:
|
|
||||||
|
|
||||||
# object creation
|
|
||||||
>>> cc=CapsCache(logger_object)
|
|
||||||
|
|
||||||
>>> caps = ('sha-1', '66/0NaeaBKkwk85efJTGmU47vXI=')
|
|
||||||
>>> muc = 'http://jabber.org/protocol/muc'
|
|
||||||
>>> chatstates = 'http://jabber.org/protocol/chatstates'
|
|
||||||
|
|
||||||
# setting data
|
|
||||||
>>> cc[caps].identities = [{'category':'client', 'type':'pc'}]
|
|
||||||
>>> cc[caps].features = [muc]
|
|
||||||
|
|
||||||
# retrieving data
|
|
||||||
>>> muc in cc[caps].features
|
|
||||||
True
|
|
||||||
>>> chatstates in cc[caps].features
|
|
||||||
False
|
|
||||||
>>> cc[caps].identities
|
|
||||||
[{'category': 'client', 'type': 'pc'}]
|
|
||||||
>>> x = cc[caps] # more efficient if making several queries for one set of caps
|
|
||||||
ATypicalBlackBoxObject
|
|
||||||
>>> muc in x.features
|
|
||||||
True
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
def __init__(self, logger=None):
|
def __init__(self, logger=None):
|
||||||
''' Create a cache for entity capabilities. '''
|
''' Create a cache for entity capabilities. '''
|
||||||
|
@ -86,12 +61,14 @@ class CapsCache(object):
|
||||||
# TODO: maybe put all known xmpp namespace strings here
|
# TODO: maybe put all known xmpp namespace strings here
|
||||||
# (strings given in xmpppy)?
|
# (strings given in xmpppy)?
|
||||||
__names = {}
|
__names = {}
|
||||||
def __init__(ciself, hash_method, hash_):
|
|
||||||
|
def __init__(self, hash_method, hash_, logger):
|
||||||
# cached into db
|
# cached into db
|
||||||
self.hash_method = hash_method
|
self.hash_method = hash_method
|
||||||
self.hash = hash_
|
self.hash = hash_
|
||||||
self._features = []
|
self._features = []
|
||||||
self._identities = []
|
self._identities = []
|
||||||
|
self._logger = logger
|
||||||
|
|
||||||
# not cached into db:
|
# not cached into db:
|
||||||
# have we sent the query?
|
# have we sent the query?
|
||||||
|
@ -106,8 +83,7 @@ class CapsCache(object):
|
||||||
def _set_features(self, value):
|
def _set_features(self, value):
|
||||||
self._features = []
|
self._features = []
|
||||||
for feature in value:
|
for feature in value:
|
||||||
self._features.append(self.__names.setdefault(feature,
|
self._features.append(self.__names.setdefault(feature, feature))
|
||||||
feature))
|
|
||||||
features = property(_get_features, _set_features)
|
features = property(_get_features, _set_features)
|
||||||
|
|
||||||
def _get_identities(self):
|
def _get_identities(self):
|
||||||
|
@ -137,7 +113,7 @@ class CapsCache(object):
|
||||||
# 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
|
||||||
|
@ -153,7 +129,7 @@ class CapsCache(object):
|
||||||
# start logging data from the net
|
# start logging data from the net
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
def load_from_db(self):
|
def initialize_from_db(self):
|
||||||
# get data from logger...
|
# get data from logger...
|
||||||
if self.logger is not None:
|
if self.logger is not None:
|
||||||
for hash_method, hash_, identities, features in \
|
for hash_method, hash_, identities, features in \
|
||||||
|
@ -169,7 +145,7 @@ class CapsCache(object):
|
||||||
|
|
||||||
hash_method, hash_ = caps
|
hash_method, hash_ = caps
|
||||||
|
|
||||||
x = self.__CacheItem(hash_method, hash_)
|
x = self.__CacheItem(hash_method, hash_, self.logger)
|
||||||
self.__cache[(hash_method, hash_)] = x
|
self.__cache[(hash_method, hash_)] = x
|
||||||
return x
|
return x
|
||||||
|
|
||||||
|
|
|
@ -216,7 +216,7 @@ class OptionsParser:
|
||||||
gajim.logger.init_vars()
|
gajim.logger.init_vars()
|
||||||
gajim.config.set('version', new_version)
|
gajim.config.set('version', new_version)
|
||||||
|
|
||||||
gajim.capscache.load_from_db()
|
gajim.capscache.initialize_from_db()
|
||||||
|
|
||||||
def update_config_x_to_09(self):
|
def update_config_x_to_09(self):
|
||||||
# Var name that changed:
|
# Var name that changed:
|
||||||
|
|
|
@ -6,36 +6,45 @@ import unittest
|
||||||
import lib
|
import lib
|
||||||
lib.setup_env()
|
lib.setup_env()
|
||||||
|
|
||||||
from common import gajim
|
|
||||||
from common import xmpp
|
|
||||||
from common import helpers
|
from common import helpers
|
||||||
|
from common.contacts import Contact
|
||||||
from common.caps import CapsCache
|
from common.caps import CapsCache
|
||||||
|
|
||||||
from mock import Mock
|
from mock import Mock
|
||||||
|
|
||||||
class MockLogger(Mock):
|
|
||||||
def __init__(self, *args):
|
class CommonCapsTest(unittest.TestCase):
|
||||||
Mock.__init__(self, *args)
|
|
||||||
|
|
||||||
class TestCapsCache(unittest.TestCase):
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.logger = MockLogger()
|
|
||||||
self.cc = CapsCache(self.logger)
|
|
||||||
|
|
||||||
self.caps_method = 'sha-1'
|
self.caps_method = 'sha-1'
|
||||||
self.caps_hash = 'zaQfb22o0UCwYDIk8KZOnoZTnrs='
|
self.caps_hash = 'RNzJvJnTWqczirzu+YF4V8am9ro='
|
||||||
self.caps = (self.caps_method, self.caps_hash)
|
self.caps = (self.caps_method, self.caps_hash)
|
||||||
self.identity = {'category': 'client', 'type': 'pc'}
|
|
||||||
|
self.node = "http://gajim.org"
|
||||||
|
self.identity = {'category': 'client', 'type': 'pc', 'name':'Gajim'}
|
||||||
|
|
||||||
self.muc = 'http://jabber.org/protocol/muc'
|
self.muc = 'http://jabber.org/protocol/muc'
|
||||||
self.chatstates = 'http://jabber.org/protocol/chatstates'
|
self.chatstates = 'http://jabber.org/protocol/chatstates'
|
||||||
|
|
||||||
self.identities = [self.identity]
|
self.identities = [self.identity]
|
||||||
self.features = [self.muc]
|
self.features = [self.muc]
|
||||||
|
|
||||||
|
|
||||||
|
class TestCapsCache(CommonCapsTest):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
CommonCapsTest.setUp(self)
|
||||||
|
|
||||||
def test_examples(self):
|
# Simulate a filled db
|
||||||
'''tests the examples given in common/caps.py'''
|
db_caps_cache = [
|
||||||
|
(self.caps_method, self.caps_hash, self.identities, self.features),
|
||||||
|
(self.caps_method, self.caps_hash, self.identities, self.features)]
|
||||||
|
self.logger = Mock(returnValues={"iter_caps_data":db_caps_cache})
|
||||||
|
|
||||||
|
self.cc = CapsCache(self.logger)
|
||||||
|
|
||||||
|
def test_set_retrieve(self):
|
||||||
|
''' Test basic set / retrieve cycle '''
|
||||||
|
|
||||||
self.cc[self.caps].identities = self.identities
|
self.cc[self.caps].identities = self.identities
|
||||||
self.cc[self.caps].features = self.features
|
self.cc[self.caps].features = self.features
|
||||||
|
@ -43,20 +52,73 @@ class TestCapsCache(unittest.TestCase):
|
||||||
self.assert_(self.muc in self.cc[self.caps].features)
|
self.assert_(self.muc in self.cc[self.caps].features)
|
||||||
self.assert_(self.chatstates not in self.cc[self.caps].features)
|
self.assert_(self.chatstates not in self.cc[self.caps].features)
|
||||||
|
|
||||||
id = self.cc[self.caps].identities
|
identities = self.cc[self.caps].identities
|
||||||
|
|
||||||
self.assertEqual(1, len(id))
|
self.assertEqual(1, len(identities))
|
||||||
|
|
||||||
id = id[0]
|
identity = identities[0]
|
||||||
self.assertEqual('client', id['category'])
|
self.assertEqual('client', identity['category'])
|
||||||
self.assertEqual('pc', id['type'])
|
self.assertEqual('pc', identity['type'])
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
''' Test caps update gets logged into db '''
|
||||||
|
|
||||||
|
item = self.cc[self.caps]
|
||||||
|
item.update(self.identities, self.features)
|
||||||
|
|
||||||
|
self.logger.mockCheckCall(0, "add_caps_entry", self.caps_method,
|
||||||
|
self.caps_hash, self.identities, self.features)
|
||||||
|
|
||||||
|
def test_initialize_from_db(self):
|
||||||
|
''' Read cashed dummy data from db '''
|
||||||
|
self.assertEqual(self.cc[self.caps].queried, 0)
|
||||||
|
self.cc.initialize_from_db()
|
||||||
|
self.assertEqual(self.cc[self.caps].queried, 2)
|
||||||
|
|
||||||
|
def test_preload_triggering_query(self):
|
||||||
|
''' Make sure that preload issues a disco '''
|
||||||
|
connection = Mock()
|
||||||
|
|
||||||
|
self.cc.preload(connection, "test@gajim.org", self.node,
|
||||||
|
self.caps_method, self.caps_hash)
|
||||||
|
|
||||||
|
connection.mockCheckCall(0, "discoverInfo", 'test@gajim.org',
|
||||||
|
'http://gajim.org#RNzJvJnTWqczirzu+YF4V8am9ro=')
|
||||||
|
|
||||||
|
def test_no_preload_query_if_cashed(self):
|
||||||
|
''' Preload must not send a query if the data is already cached '''
|
||||||
|
connection = Mock()
|
||||||
|
|
||||||
|
self.cc.initialize_from_db()
|
||||||
|
self.cc.preload(connection, "test@gajim.org", self.node,
|
||||||
|
self.caps_method, self.caps_hash)
|
||||||
|
|
||||||
|
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, self.chatstates),
|
||||||
|
msg="Assume everything is supported, if we don't have caps")
|
||||||
|
|
||||||
|
self.cc.initialize_from_db()
|
||||||
|
|
||||||
|
self.assertFalse(self.cc.is_supported(contact, self.chatstates),
|
||||||
|
msg="Must return false on unsupported feature")
|
||||||
|
|
||||||
|
self.assertTrue(self.cc.is_supported(contact, self.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)
|
||||||
|
|
||||||
self.assertEqual(self.caps_hash, computed_hash)
|
self.assertEqual(self.caps_hash, computed_hash)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue