Improve common/caps.py test coverage.

This commit is contained in:
Stephan Erb 2009-10-25 21:17:32 +01:00
parent 2ca65bf6da
commit 0440aec980
3 changed files with 94 additions and 56 deletions

View File

@ -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

View File

@ -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:

View File

@ -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()