- renamed src/common/nslookup.py to resolver.py
- refactored resolver code and added asynchronous resolver based on patch by Damien Thebault[1] * Uses libasyncns-python[2]. If it's not available, old nslookup resolver is used) * works for SRV requests only at the moment [1] https://www.lagaule.org/pipermail/gajim-devel/2008-July/000460.html [2] https://code.launchpad.net/libasyncns-python
This commit is contained in:
parent
ed7dd84cfe
commit
a7c36048b9
|
@ -1,4 +1,4 @@
|
||||||
## common/nslookup.py
|
## common/resolver.py
|
||||||
##
|
##
|
||||||
## Copyright (C) 2006 Dimitur Kirov <dkirov@gmail.com>
|
## Copyright (C) 2006 Dimitur Kirov <dkirov@gmail.com>
|
||||||
##
|
##
|
||||||
|
@ -23,6 +23,7 @@ import re
|
||||||
|
|
||||||
from xmpp.idlequeue import *
|
from xmpp.idlequeue import *
|
||||||
|
|
||||||
|
# needed for nslookup
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
from subprocess import * # python24 only. we ask this for Windows
|
from subprocess import * # python24 only. we ask this for Windows
|
||||||
elif os.name == 'posix':
|
elif os.name == 'posix':
|
||||||
|
@ -34,13 +35,138 @@ ns_type_pattern = re.compile('^[a-z]+$')
|
||||||
# match srv host_name
|
# match srv host_name
|
||||||
host_pattern = re.compile('^[a-z0-9\-._]*[a-z0-9]\.[a-z]{2,}$')
|
host_pattern = re.compile('^[a-z0-9\-._]*[a-z0-9]\.[a-z]{2,}$')
|
||||||
|
|
||||||
class Resolver:
|
USE_LIBASYNCNS = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
#raise ImportError("Manually disabled libasync")
|
||||||
|
import libasyncns
|
||||||
|
USE_LIBASYNCNS = True
|
||||||
|
log.info("libasyncns-python loaded")
|
||||||
|
except ImportError:
|
||||||
|
log.debug("Import of libasyncns-python failed, getaddrinfo will block", exc_info=True)
|
||||||
|
|
||||||
|
# FIXME: Remove these prints before release, replace with a warning dialog.
|
||||||
|
print >> sys.stderr, "=" * 79
|
||||||
|
print >> sys.stderr, "libasyncns-python not installed which means:"
|
||||||
|
print >> sys.stderr, " - nslookup will be used for SRV and TXT requests"
|
||||||
|
print >> sys.stderr, " - getaddrinfo will block"
|
||||||
|
print >> sys.stderr, "libasyncns-python can be found at https://launchpad.net/libasyncns-python"
|
||||||
|
print >> sys.stderr, "=" * 79
|
||||||
|
|
||||||
|
|
||||||
|
def get_resolver(idlequeue):
|
||||||
|
if USE_LIBASYNCNS:
|
||||||
|
return LibAsyncNSResolver()
|
||||||
|
else:
|
||||||
|
return NSLookupResolver(idlequeue)
|
||||||
|
|
||||||
|
class CommonResolver():
|
||||||
|
def __init__(self):
|
||||||
|
# dict {"host+type" : list of records}
|
||||||
|
self.resolved_hosts = {}
|
||||||
|
# dict {"host+type" : list of callbacks}
|
||||||
|
self.handlers = {}
|
||||||
|
|
||||||
|
def resolve(self, host, on_ready, type='srv'):
|
||||||
|
assert(type in ['srv', 'txt'])
|
||||||
|
if not host:
|
||||||
|
# empty host, return empty list of srv records
|
||||||
|
on_ready([])
|
||||||
|
return
|
||||||
|
if self.resolved_hosts.has_key(host+type):
|
||||||
|
# host is already resolved, return cached values
|
||||||
|
on_ready(host, self.resolved_hosts[host+type])
|
||||||
|
return
|
||||||
|
if self.handlers.has_key(host+type):
|
||||||
|
# host is about to be resolved by another connection,
|
||||||
|
# attach our callback
|
||||||
|
self.handlers[host+type].append(on_ready)
|
||||||
|
else:
|
||||||
|
# host has never been resolved, start now
|
||||||
|
self.handlers[host+type] = [on_ready]
|
||||||
|
self.start_resolve(host, type)
|
||||||
|
|
||||||
|
def _on_ready(self, host, type, result_list):
|
||||||
|
# practically it is impossible to be the opposite, but who knows :)
|
||||||
|
if not self.resolved_hosts.has_key(host+type):
|
||||||
|
self.resolved_hosts[host+type] = result_list
|
||||||
|
if self.handlers.has_key(host+type):
|
||||||
|
for callback in self.handlers[host+type]:
|
||||||
|
callback(host, result_list)
|
||||||
|
del(self.handlers[host+type])
|
||||||
|
|
||||||
|
def start_resolve(self, host, type):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LibAsyncNSResolver(CommonResolver):
|
||||||
|
'''
|
||||||
|
Asynchronous resolver using libasyncns-python. process() method has to be called
|
||||||
|
in order to proceed the pending requests.
|
||||||
|
Based on patch submitted by Damien Thebault.
|
||||||
|
'''
|
||||||
|
def __init__(self):
|
||||||
|
self.asyncns = libasyncns.Asyncns()
|
||||||
|
CommonResolver.__init__(self)
|
||||||
|
|
||||||
|
def start_resolve(self, host, type):
|
||||||
|
type = libasyncns.ns_t_srv
|
||||||
|
if type == 'txt': type = libasyncns.ns_t_txt
|
||||||
|
resq = self.asyncns.res_query(host, libasyncns.ns_c_in, type)
|
||||||
|
resq.userdata = {'host':host, 'type':type}
|
||||||
|
|
||||||
|
# getaddrinfo to be done
|
||||||
|
#def resolve_name(self, dname, callback):
|
||||||
|
#resq = self.asyncns.getaddrinfo(dname)
|
||||||
|
#resq.userdata = {'callback':callback, 'dname':dname}
|
||||||
|
|
||||||
|
def _on_ready(self, host, type, result_list):
|
||||||
|
if type == libasyncns.ns_t_srv: type = 'srv'
|
||||||
|
elif type == libasyncns.ns_t_txt: type = 'txt'
|
||||||
|
|
||||||
|
CommonResolver._on_ready(self, host, type, result_list)
|
||||||
|
|
||||||
|
|
||||||
|
def process(self):
|
||||||
|
try:
|
||||||
|
self.asyncns.wait(False)
|
||||||
|
resq = self.asyncns.get_next()
|
||||||
|
except:
|
||||||
|
return True
|
||||||
|
if type(resq) == libasyncns.ResQuery:
|
||||||
|
# TXT or SRV result
|
||||||
|
while resq is not None:
|
||||||
|
try:
|
||||||
|
rl = resq.get_done()
|
||||||
|
except:
|
||||||
|
rl = []
|
||||||
|
if rl:
|
||||||
|
for r in rl:
|
||||||
|
r['prio'] = r['pref']
|
||||||
|
self._on_ready(
|
||||||
|
host = resq.userdata['host'],
|
||||||
|
type = resq.userdata['type'],
|
||||||
|
result_list = rl)
|
||||||
|
try:
|
||||||
|
resq = self.asyncns.get_next()
|
||||||
|
except:
|
||||||
|
resq = None
|
||||||
|
elif type(resq) == libasyncns.AddrInfoQuery:
|
||||||
|
# getaddrinfo result (A or AAAA)
|
||||||
|
rl = resq.get_done()
|
||||||
|
resq.userdata['callback'](resq.userdata['dname'], rl)
|
||||||
|
return True
|
||||||
|
|
||||||
|
class NSLookupResolver(CommonResolver):
|
||||||
|
'''
|
||||||
|
Asynchronous DNS resolver calling nslookup. Processing of pending requests
|
||||||
|
is invoked from idlequeue which is watching file descriptor of pipe of stdout
|
||||||
|
of nslookup process.
|
||||||
|
'''
|
||||||
def __init__(self, idlequeue):
|
def __init__(self, idlequeue):
|
||||||
self.idlequeue = idlequeue
|
self.idlequeue = idlequeue
|
||||||
# dict {host : list of srv records}
|
self.process = False
|
||||||
self.resolved_hosts = {}
|
CommonResolver.__init__(self)
|
||||||
# dict {host : list of callbacks}
|
|
||||||
self.handlers = {}
|
|
||||||
|
|
||||||
def parse_srv_result(self, fqdn, result):
|
def parse_srv_result(self, fqdn, result):
|
||||||
''' parse the output of nslookup command and return list of
|
''' parse the output of nslookup command and return list of
|
||||||
|
@ -133,42 +259,19 @@ class Resolver:
|
||||||
'prio': prio})
|
'prio': prio})
|
||||||
return hosts
|
return hosts
|
||||||
|
|
||||||
def _on_ready(self, host, result):
|
def _on_ready(self, host, type, result):
|
||||||
# nslookup finished, parse the result and call the handlers
|
# nslookup finished, parse the result and call the handlers
|
||||||
result_list = self.parse_srv_result(host, result)
|
result_list = self.parse_srv_result(host, result)
|
||||||
|
CommonResolver._on_ready(self, host, type, result_list)
|
||||||
|
|
||||||
# practically it is impossible to be the opposite, but who knows :)
|
|
||||||
if not self.resolved_hosts.has_key(host):
|
|
||||||
self.resolved_hosts[host] = result_list
|
|
||||||
if self.handlers.has_key(host):
|
|
||||||
for callback in self.handlers[host]:
|
|
||||||
callback(host, result_list)
|
|
||||||
del(self.handlers[host])
|
|
||||||
|
|
||||||
def start_resolve(self, host):
|
def start_resolve(self, host, type):
|
||||||
''' spawn new nslookup process and start waiting for results '''
|
''' spawn new nslookup process and start waiting for results '''
|
||||||
ns = NsLookup(self._on_ready, host)
|
ns = NsLookup(self._on_ready, host, type)
|
||||||
ns.set_idlequeue(self.idlequeue)
|
ns.set_idlequeue(self.idlequeue)
|
||||||
ns.commandtimeout = 10
|
ns.commandtimeout = 10
|
||||||
ns.start()
|
ns.start()
|
||||||
|
|
||||||
def resolve(self, host, on_ready):
|
|
||||||
if not host:
|
|
||||||
# empty host, return empty list of srv records
|
|
||||||
on_ready([])
|
|
||||||
return
|
|
||||||
if self.resolved_hosts.has_key(host):
|
|
||||||
# host is already resolved, return cached values
|
|
||||||
on_ready(host, self.resolved_hosts[host])
|
|
||||||
return
|
|
||||||
if self.handlers.has_key(host):
|
|
||||||
# host is about to be resolved by another connection,
|
|
||||||
# attach our callback
|
|
||||||
self.handlers[host].append(on_ready)
|
|
||||||
else:
|
|
||||||
# host has never been resolved, start now
|
|
||||||
self.handlers[host] = [on_ready]
|
|
||||||
self.start_resolve(host)
|
|
||||||
|
|
||||||
# TODO: move IdleCommand class in other file, maybe helpers ?
|
# TODO: move IdleCommand class in other file, maybe helpers ?
|
||||||
class IdleCommand(IdleObject):
|
class IdleCommand(IdleObject):
|
||||||
|
@ -268,7 +371,7 @@ class IdleCommand(IdleObject):
|
||||||
self._return_result()
|
self._return_result()
|
||||||
|
|
||||||
class NsLookup(IdleCommand):
|
class NsLookup(IdleCommand):
|
||||||
def __init__(self, on_result, host='_xmpp-client', type = 'srv'):
|
def __init__(self, on_result, host='_xmpp-client', type='srv'):
|
||||||
IdleCommand.__init__(self, on_result)
|
IdleCommand.__init__(self, on_result)
|
||||||
self.commandtimeout = 10
|
self.commandtimeout = 10
|
||||||
self.host = host.lower()
|
self.host = host.lower()
|
||||||
|
@ -288,7 +391,7 @@ class NsLookup(IdleCommand):
|
||||||
|
|
||||||
def _return_result(self):
|
def _return_result(self):
|
||||||
if self.result_handler:
|
if self.result_handler:
|
||||||
self.result_handler(self.host, self.result)
|
self.result_handler(self.host, self.type, self.result)
|
||||||
self.result_handler = None
|
self.result_handler = None
|
||||||
|
|
||||||
# below lines is on how to use API and assist in testing
|
# below lines is on how to use API and assist in testing
|
|
@ -40,6 +40,7 @@ class NonBlockingClient:
|
||||||
:param domain: domain - for to: attribute (from account info)
|
:param domain: domain - for to: attribute (from account info)
|
||||||
:param idlequeue: processing idlequeue
|
:param idlequeue: processing idlequeue
|
||||||
:param caller: calling object - it has to implement method _event_dispatcher
|
:param caller: calling object - it has to implement method _event_dispatcher
|
||||||
|
which is called from dispatcher instance
|
||||||
'''
|
'''
|
||||||
self.Namespace = protocol.NS_CLIENT
|
self.Namespace = protocol.NS_CLIENT
|
||||||
self.defaultNamespace = self.Namespace
|
self.defaultNamespace = self.Namespace
|
||||||
|
|
|
@ -260,7 +260,7 @@ import common.sleepy
|
||||||
|
|
||||||
from common.xmpp import idlequeue
|
from common.xmpp import idlequeue
|
||||||
from common.zeroconf import connection_zeroconf
|
from common.zeroconf import connection_zeroconf
|
||||||
from common import nslookup
|
from common import resolver
|
||||||
from common import proxy65_manager
|
from common import proxy65_manager
|
||||||
from common import socks5
|
from common import socks5
|
||||||
from common import helpers
|
from common import helpers
|
||||||
|
@ -3077,7 +3077,7 @@ class Interface:
|
||||||
# gajim.idlequeue.process() each foo miliseconds
|
# gajim.idlequeue.process() each foo miliseconds
|
||||||
gajim.idlequeue = GlibIdleQueue()
|
gajim.idlequeue = GlibIdleQueue()
|
||||||
# resolve and keep current record of resolved hosts
|
# resolve and keep current record of resolved hosts
|
||||||
gajim.resolver = nslookup.Resolver(gajim.idlequeue)
|
gajim.resolver = resolver.get_resolver(gajim.idlequeue)
|
||||||
gajim.socks5queue = socks5.SocksQueue(gajim.idlequeue,
|
gajim.socks5queue = socks5.SocksQueue(gajim.idlequeue,
|
||||||
self.handle_event_file_rcv_completed,
|
self.handle_event_file_rcv_completed,
|
||||||
self.handle_event_file_progress)
|
self.handle_event_file_progress)
|
||||||
|
@ -3222,6 +3222,11 @@ class Interface:
|
||||||
self.last_ftwindow_update = 0
|
self.last_ftwindow_update = 0
|
||||||
|
|
||||||
gobject.timeout_add(100, self.autoconnect)
|
gobject.timeout_add(100, self.autoconnect)
|
||||||
|
|
||||||
|
# when using libasyncns we need to process resolver in regular intervals
|
||||||
|
if resolver.USE_LIBASYNCNS:
|
||||||
|
gobject.timeout_add(200, gajim.resolver.process)
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
gobject.timeout_add(200, self.process_connections)
|
gobject.timeout_add(200, self.process_connections)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
import sys
|
||||||
|
import os.path
|
||||||
|
import getopt
|
||||||
|
|
||||||
|
use_x = True
|
||||||
|
shortargs = 'hnv:'
|
||||||
|
longargs = 'help no-x verbose='
|
||||||
|
opts, args = getopt.getopt(sys.argv[1:], shortargs, longargs.split())
|
||||||
|
for o, a in opts:
|
||||||
|
if o in ('-n', '--no-x'):
|
||||||
|
use_x = False
|
||||||
|
|
||||||
|
gajim_root = os.path.join(os.path.abspath(os.path.dirname(__file__)), '../..')
|
||||||
|
|
||||||
|
# look for modules in the CWD, then gajim/test/lib, then gajim/src, then everywhere else
|
||||||
|
sys.path.insert(1, gajim_root + '/src')
|
||||||
|
sys.path.insert(1, gajim_root + '/test/lib')
|
||||||
|
|
||||||
|
# a temporary version of ~/.gajim for testing
|
||||||
|
configdir = gajim_root + '/test/tmp'
|
||||||
|
|
||||||
|
# define _ for i18n
|
||||||
|
import __builtin__
|
||||||
|
__builtin__._ = lambda x: x
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
def setup_env():
|
||||||
|
# wipe config directory
|
||||||
|
if os.path.isdir(configdir):
|
||||||
|
import shutil
|
||||||
|
shutil.rmtree(configdir)
|
||||||
|
|
||||||
|
os.mkdir(configdir)
|
||||||
|
|
||||||
|
import common.configpaths
|
||||||
|
common.configpaths.gajimpaths.init(configdir)
|
||||||
|
common.configpaths.gajimpaths.init_profile()
|
||||||
|
|
||||||
|
# for some reason common.gajim needs to be imported before xmpppy?
|
||||||
|
from common import gajim
|
||||||
|
|
||||||
|
gajim.DATA_DIR = gajim_root + '/data'
|
||||||
|
gajim.use_x = use_x
|
||||||
|
|
||||||
|
if use_x:
|
||||||
|
import gtkgui_helpers
|
||||||
|
gtkgui_helpers.GLADE_DIR = gajim_root + '/data/glade'
|
||||||
|
|
||||||
|
# vim: se ts=3:
|
|
@ -0,0 +1,77 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
account1 = u'acc1'
|
||||||
|
account2 = u'Cool"chârßéµö'
|
||||||
|
account3 = u'dingdong.org'
|
||||||
|
|
||||||
|
contacts = {}
|
||||||
|
contacts[account1] = {
|
||||||
|
u'myjid@'+account1: {
|
||||||
|
'ask': None, 'groups': [], 'name': None, 'resources': {},
|
||||||
|
'subscription': u'both'},
|
||||||
|
u'default1@gajim.org': {
|
||||||
|
'ask': None, 'groups': [], 'name': None, 'resources': {},
|
||||||
|
'subscription': u'both'},
|
||||||
|
u'default2@gajim.org': {
|
||||||
|
'ask': None, 'groups': [u'GroupA',], 'name': None, 'resources': {},
|
||||||
|
'subscription': u'both'},
|
||||||
|
u'Cool"chârßéµö@gajim.org': {
|
||||||
|
'ask': None, 'groups': [u'<Cool"chârßéµö', u'GroupB'],
|
||||||
|
'name': None, 'resources': {}, 'subscription': u'both'},
|
||||||
|
u'samejid@gajim.org': {
|
||||||
|
'ask': None, 'groups': [u'GroupA',], 'name': None, 'resources': {},
|
||||||
|
'subscription': u'both'}
|
||||||
|
}
|
||||||
|
contacts[account2] = {
|
||||||
|
u'myjid@'+account2: {
|
||||||
|
'ask': None, 'groups': [], 'name': None, 'resources': {},
|
||||||
|
'subscription': u'both'},
|
||||||
|
u'default3@gajim.org': {
|
||||||
|
'ask': None, 'groups': [u'GroupC',], 'name': None, 'resources': {},
|
||||||
|
'subscription': u'both'},
|
||||||
|
u'asksubfrom@gajim.org': {
|
||||||
|
'ask': u'subscribe', 'groups': [u'GroupA',], 'name': None,
|
||||||
|
'resources': {}, 'subscription': u'from'},
|
||||||
|
u'subto@gajim.org': {
|
||||||
|
'ask': None, 'groups': [u'GroupB'], 'name': None, 'resources': {},
|
||||||
|
'subscription': u'to'},
|
||||||
|
u'samejid@gajim.org': {
|
||||||
|
'ask': None, 'groups': [u'GroupA', u'GroupB'], 'name': None,
|
||||||
|
'resources': {}, 'subscription': u'both'}
|
||||||
|
}
|
||||||
|
contacts[account3] = {
|
||||||
|
#u'guypsych0\\40h.com@msn.dingdong.org': {
|
||||||
|
# 'ask': None, 'groups': [], 'name': None, 'resources': {},
|
||||||
|
# 'subscription': u'both'},
|
||||||
|
u'guypsych0%h.com@msn.delx.cjb.net': {
|
||||||
|
'ask': u'subscribe', 'groups': [], 'name': None,
|
||||||
|
'resources': {}, 'subscription': u'from'},
|
||||||
|
#u'guypsych0%h.com@msn.jabber.wiretrip.org': {
|
||||||
|
# 'ask': None, 'groups': [], 'name': None, 'resources': {},
|
||||||
|
# 'subscription': u'to'},
|
||||||
|
#u'guypsycho\\40g.com@gtalk.dingdong.org': {
|
||||||
|
# 'ask': None, 'groups': [], 'name': None,
|
||||||
|
# 'resources': {}, 'subscription': u'both'}
|
||||||
|
}
|
||||||
|
# We have contacts that are not in roster but only specified in the metadata
|
||||||
|
metacontact_data = [
|
||||||
|
[{'account': account3,
|
||||||
|
'jid': u'guypsych0\\40h.com@msn.dingdong.org',
|
||||||
|
'order': 0},
|
||||||
|
{'account': account3,
|
||||||
|
'jid': u'guypsych0%h.com@msn.delx.cjb.net',
|
||||||
|
'order': 0},
|
||||||
|
{'account': account3,
|
||||||
|
'jid': u'guypsych0%h.com@msn.jabber.wiretrip.org',
|
||||||
|
'order': 0},
|
||||||
|
{'account': account3,
|
||||||
|
'jid': u'guypsycho\\40g.com@gtalk.dingdong.org',
|
||||||
|
'order': 0}],
|
||||||
|
|
||||||
|
[{'account': account1,
|
||||||
|
'jid': u'samejid@gajim.org',
|
||||||
|
'order': 0},
|
||||||
|
{'account': account2,
|
||||||
|
'jid': u'samejid@gajim.org',
|
||||||
|
'order': 0}]
|
||||||
|
]
|
||||||
|
|
|
@ -463,3 +463,5 @@ CALLABLE = callable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# vim: se ts=3:
|
|
@ -0,0 +1,145 @@
|
||||||
|
# gajim-specific mock objects
|
||||||
|
from mock import Mock
|
||||||
|
|
||||||
|
from common import gajim
|
||||||
|
|
||||||
|
from common.connection_handlers import ConnectionHandlersBase
|
||||||
|
|
||||||
|
class MockConnection(Mock, ConnectionHandlersBase):
|
||||||
|
def __init__(self, account, *args):
|
||||||
|
Mock.__init__(self, *args)
|
||||||
|
ConnectionHandlersBase.__init__(self)
|
||||||
|
|
||||||
|
self.name = account
|
||||||
|
self.connected = 2
|
||||||
|
self.mood = {}
|
||||||
|
self.activity = {}
|
||||||
|
self.tune = {}
|
||||||
|
self.blocked_contacts = {}
|
||||||
|
self.blocked_groups = {}
|
||||||
|
self.sessions = {}
|
||||||
|
|
||||||
|
gajim.interface.instances[account] = {'infos': {}, 'disco': {},
|
||||||
|
'gc_config': {}, 'search': {}}
|
||||||
|
gajim.interface.minimized_controls[account] = {}
|
||||||
|
gajim.contacts.add_account(account)
|
||||||
|
gajim.groups[account] = {}
|
||||||
|
gajim.gc_connected[account] = {}
|
||||||
|
gajim.automatic_rooms[account] = {}
|
||||||
|
gajim.newly_added[account] = []
|
||||||
|
gajim.to_be_removed[account] = []
|
||||||
|
gajim.nicks[account] = gajim.config.get_per('accounts', account, 'name')
|
||||||
|
gajim.block_signed_in_notifications[account] = True
|
||||||
|
gajim.sleeper_state[account] = 0
|
||||||
|
gajim.encrypted_chats[account] = []
|
||||||
|
gajim.last_message_time[account] = {}
|
||||||
|
gajim.status_before_autoaway[account] = ''
|
||||||
|
gajim.transport_avatar[account] = {}
|
||||||
|
gajim.gajim_optional_features[account] = []
|
||||||
|
gajim.caps_hash[account] = ''
|
||||||
|
|
||||||
|
gajim.connections[account] = self
|
||||||
|
|
||||||
|
class MockWindow(Mock):
|
||||||
|
def __init__(self, *args):
|
||||||
|
Mock.__init__(self, *args)
|
||||||
|
self.window = Mock()
|
||||||
|
self._controls = {}
|
||||||
|
|
||||||
|
def get_control(self, jid, account):
|
||||||
|
try:
|
||||||
|
return self._controls[account][jid]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def has_control(self, jid, acct):
|
||||||
|
return self.get_control(jid, acct) is not None
|
||||||
|
|
||||||
|
def new_tab(self, ctrl):
|
||||||
|
account = ctrl.account
|
||||||
|
jid = ctrl.jid
|
||||||
|
|
||||||
|
if account not in self._controls:
|
||||||
|
self._controls[account] = {}
|
||||||
|
|
||||||
|
if jid not in self._controls[account]:
|
||||||
|
self._controls[account][jid] = {}
|
||||||
|
|
||||||
|
self._controls[account][jid] = ctrl
|
||||||
|
|
||||||
|
def __nonzero__(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
class MockChatControl(Mock):
|
||||||
|
def __init__(self, jid, account, *args):
|
||||||
|
Mock.__init__(self, *args)
|
||||||
|
|
||||||
|
self.jid = jid
|
||||||
|
self.account = account
|
||||||
|
|
||||||
|
self.parent_win = MockWindow({'get_active_control': self})
|
||||||
|
self.session = None
|
||||||
|
|
||||||
|
def set_session(self, sess):
|
||||||
|
self.session = sess
|
||||||
|
|
||||||
|
def __nonzero__(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self is other
|
||||||
|
|
||||||
|
class MockInterface(Mock):
|
||||||
|
def __init__(self, *args):
|
||||||
|
Mock.__init__(self, *args)
|
||||||
|
gajim.interface = self
|
||||||
|
self.msg_win_mgr = Mock()
|
||||||
|
self.roster = Mock()
|
||||||
|
|
||||||
|
self.remote_ctrl = None
|
||||||
|
self.instances = {}
|
||||||
|
self.minimized_controls = {}
|
||||||
|
self.status_sent_to_users = Mock()
|
||||||
|
|
||||||
|
if gajim.use_x:
|
||||||
|
self.jabber_state_images = {'16': {}, '32': {}, 'opened': {},
|
||||||
|
'closed': {}}
|
||||||
|
|
||||||
|
import gtkgui_helpers
|
||||||
|
gtkgui_helpers.make_jabber_state_images()
|
||||||
|
else:
|
||||||
|
self.jabber_state_images = {'16': Mock(), '32': Mock(),
|
||||||
|
'opened': Mock(), 'closed': Mock()}
|
||||||
|
|
||||||
|
class MockLogger(Mock):
|
||||||
|
def __init__(self):
|
||||||
|
Mock.__init__(self, {'write': None, 'get_transports_type': {}})
|
||||||
|
|
||||||
|
class MockContact(Mock):
|
||||||
|
def __nonzero__(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
import random
|
||||||
|
|
||||||
|
class MockSession(Mock):
|
||||||
|
def __init__(self, conn, jid, thread_id, type):
|
||||||
|
Mock.__init__(self)
|
||||||
|
|
||||||
|
self.conn = conn
|
||||||
|
self.jid = jid
|
||||||
|
self.type = type
|
||||||
|
self.thread_id = thread_id
|
||||||
|
|
||||||
|
if not self.thread_id:
|
||||||
|
self.thread_id = '%0x' % random.randint(0, 10000)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<MockSession %s>' % self.thread_id
|
||||||
|
|
||||||
|
def __nonzero__(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self is other
|
||||||
|
|
||||||
|
# vim: se ts=3:
|
|
@ -13,3 +13,5 @@ def get_show_in_roster(event, account, contact, session = None):
|
||||||
|
|
||||||
def get_show_in_systray(event, account, contact, type_ = None):
|
def get_show_in_systray(event, account, contact, type_ = None):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# vim: se ts=3:
|
|
@ -1,68 +0,0 @@
|
||||||
# gajim-specific mock objects
|
|
||||||
from mock import Mock
|
|
||||||
|
|
||||||
from common import gajim
|
|
||||||
|
|
||||||
class MockConnection(Mock):
|
|
||||||
def __init__(self, name, *args):
|
|
||||||
Mock.__init__(self, *args)
|
|
||||||
self.name = name
|
|
||||||
gajim.connections[name] = self
|
|
||||||
|
|
||||||
class MockWindow(Mock):
|
|
||||||
def __init__(self, *args):
|
|
||||||
Mock.__init__(self, *args)
|
|
||||||
self.window = Mock()
|
|
||||||
|
|
||||||
class MockChatControl(Mock):
|
|
||||||
def __init__(self, *args):
|
|
||||||
Mock.__init__(self, *args)
|
|
||||||
|
|
||||||
self.parent_win = MockWindow({'get_active_control': self})
|
|
||||||
self.session = None
|
|
||||||
|
|
||||||
def set_session(self, sess):
|
|
||||||
self.session = sess
|
|
||||||
|
|
||||||
def __nonzero__(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return self is other
|
|
||||||
|
|
||||||
class MockInterface(Mock):
|
|
||||||
def __init__(self, acct, *args):
|
|
||||||
Mock.__init__(self, *args)
|
|
||||||
self.msg_win_mgr = Mock()
|
|
||||||
self.roster = Mock()
|
|
||||||
|
|
||||||
self.remote_ctrl = None
|
|
||||||
self.minimized_controls = { acct: {} }
|
|
||||||
|
|
||||||
class MockLogger(Mock):
|
|
||||||
def __init__(self):
|
|
||||||
Mock.__init__(self, {'write': None})
|
|
||||||
|
|
||||||
class MockContact(Mock):
|
|
||||||
def __nonzero__(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
import random
|
|
||||||
|
|
||||||
class MockSession(Mock):
|
|
||||||
def __init__(self, conn, jid, thread_id, type):
|
|
||||||
Mock.__init__(self)
|
|
||||||
|
|
||||||
self.conn = conn
|
|
||||||
self.jid = jid
|
|
||||||
self.type = type
|
|
||||||
self.thread_id = thread_id
|
|
||||||
|
|
||||||
if not self.thread_id:
|
|
||||||
self.thread_id = '%0x' % random.randint(0, 10000)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
print '<MockSession %s>' % self.thread_id
|
|
||||||
|
|
||||||
def __nonzero__(self):
|
|
||||||
return True
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
import lib
|
||||||
|
lib.setup_env()
|
||||||
|
|
||||||
|
from common import resolver
|
||||||
|
from gajim import GlibIdleQueue
|
||||||
|
|
||||||
|
from mock import Mock, expectParams
|
||||||
|
from mocks import *
|
||||||
|
|
||||||
|
import gtk
|
||||||
|
|
||||||
|
|
||||||
|
GMAIL_SRV_NAME = '_xmpp-client._tcp.gmail.com'
|
||||||
|
NONSENSE_NAME = 'sfsdfsdfsdf.sdfs.fsd'
|
||||||
|
JABBERCZ_TXT_NAME = '_xmppconnect.jabber.cz'
|
||||||
|
JABBERCZ_SRV_NAME = '_xmpp-client._tcp.jabber.cz'
|
||||||
|
|
||||||
|
TEST_LIST = [(GMAIL_SRV_NAME, 'srv', True),
|
||||||
|
(NONSENSE_NAME, 'srv', False),
|
||||||
|
(JABBERCZ_SRV_NAME, 'srv', True)]
|
||||||
|
|
||||||
|
class TestResolver(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.iq = GlibIdleQueue()
|
||||||
|
self.reset()
|
||||||
|
self.resolver = None
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.flag = False
|
||||||
|
self.expect_results = False
|
||||||
|
self.nslookup = False
|
||||||
|
self.resolver = None
|
||||||
|
|
||||||
|
def testLibAsyncNSResolver(self):
|
||||||
|
self.reset()
|
||||||
|
if not resolver.USE_LIBASYNCNS:
|
||||||
|
print 'testLibAsyncResolver: libasyncns-python not installed'
|
||||||
|
return
|
||||||
|
self.resolver = resolver.LibAsyncNSResolver()
|
||||||
|
|
||||||
|
for name, type, expect_results in TEST_LIST:
|
||||||
|
self.expect_results = expect_results
|
||||||
|
self.runLANSR(name, type)
|
||||||
|
self.flag = False
|
||||||
|
|
||||||
|
def runLANSR(self, name, type):
|
||||||
|
self.resolver.resolve(
|
||||||
|
host = name,
|
||||||
|
type = type,
|
||||||
|
on_ready = self.myonready)
|
||||||
|
while not self.flag:
|
||||||
|
time.sleep(1)
|
||||||
|
self.resolver.process()
|
||||||
|
|
||||||
|
|
||||||
|
def myonready(self, name, result_set):
|
||||||
|
print 'on_ready called ...'
|
||||||
|
print 'hostname: %s' % name
|
||||||
|
print 'result set: %s' % result_set
|
||||||
|
print 'res.resolved_hosts: %s' % self.resolver.resolved_hosts
|
||||||
|
if self.expect_results:
|
||||||
|
self.assert_(len(result_set) > 0)
|
||||||
|
else:
|
||||||
|
self.assert_(result_set == [])
|
||||||
|
self.flag = True
|
||||||
|
if self.nslookup: self._testNSLR()
|
||||||
|
|
||||||
|
|
||||||
|
def testNSLookupResolver(self):
|
||||||
|
self.reset()
|
||||||
|
self.nslookup = True
|
||||||
|
self.resolver = resolver.NSLookupResolver(self.iq)
|
||||||
|
self.test_list = TEST_LIST
|
||||||
|
self._testNSLR()
|
||||||
|
try:
|
||||||
|
gtk.main()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print 'KeyboardInterrupt caught'
|
||||||
|
|
||||||
|
def _testNSLR(self):
|
||||||
|
if self.test_list == []:
|
||||||
|
gtk.main_quit()
|
||||||
|
return
|
||||||
|
name, type, self.expect_results = self.test_list.pop()
|
||||||
|
self.resolver.resolve(
|
||||||
|
host = name,
|
||||||
|
type = type,
|
||||||
|
on_ready = self.myonready)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
Loading…
Reference in New Issue