Make MumoManager testable. Add first basic tests to test case. MumoManager is not yet completed.
This commit is contained in:
30
config.py
30
config.py
@@ -37,26 +37,36 @@ class Config(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, filename = None, default = None):
|
def __init__(self, filename = None, default = None):
|
||||||
if not filename or not default: return
|
if (filename and not default) or \
|
||||||
cfg = ConfigParser.ConfigParser()
|
(not filename and not default): return
|
||||||
cfg.optionxform = str
|
|
||||||
cfg.read(filename)
|
if filename:
|
||||||
|
cfg = ConfigParser.ConfigParser()
|
||||||
|
cfg.optionxform = str
|
||||||
|
cfg.read(filename)
|
||||||
|
|
||||||
for h,v in default.iteritems():
|
for h,v in default.iteritems():
|
||||||
if not v:
|
if not v:
|
||||||
# Output this whole section as a list of raw key/value tuples
|
# Output this whole section as a list of raw key/value tuples
|
||||||
try:
|
if not filename:
|
||||||
self.__dict__[h] = cfg.items(h)
|
|
||||||
except ConfigParser.NoSectionError:
|
|
||||||
self.__dict__[h] = []
|
self.__dict__[h] = []
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
self.__dict__[h] = cfg.items(h)
|
||||||
|
except ConfigParser.NoSectionError:
|
||||||
|
self.__dict__[h] = []
|
||||||
else:
|
else:
|
||||||
self.__dict__[h] = Config()
|
self.__dict__[h] = Config()
|
||||||
for name, val in v.iteritems():
|
for name, val in v.iteritems():
|
||||||
conv, vdefault = val
|
conv, vdefault = val
|
||||||
try:
|
|
||||||
self.__dict__[h].__dict__[name] = conv(cfg.get(h, name))
|
if not filename:
|
||||||
except (ValueError, ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
|
||||||
self.__dict__[h].__dict__[name] = vdefault
|
self.__dict__[h].__dict__[name] = vdefault
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
self.__dict__[h].__dict__[name] = conv(cfg.get(h, name))
|
||||||
|
except (ValueError, ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
||||||
|
self.__dict__[h].__dict__[name] = vdefault
|
||||||
|
|
||||||
def x2bool(s):
|
def x2bool(s):
|
||||||
"""Helper function to convert strings from the config to bool"""
|
"""Helper function to convert strings from the config to bool"""
|
||||||
|
@@ -105,6 +105,12 @@ testfallbacknum = asdas
|
|||||||
finally:
|
finally:
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
|
|
||||||
|
def testLoadDefault(self):
|
||||||
|
cfg = Config(default=self.cfg_default)
|
||||||
|
assert(cfg.world.domination == False)
|
||||||
|
assert(cfg.somethingelse.bla == "test")
|
||||||
|
assert(cfg.world.somenum == 0)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
#import sys;sys.argv = ['', 'Test.testName']
|
#import sys;sys.argv = ['', 'Test.testName']
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
import Queue
|
import Queue
|
||||||
from worker import Worker, local_thread, local_thread_blocking
|
from worker import Worker, local_thread, local_thread_blocking
|
||||||
|
from config import Config
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@@ -47,18 +48,22 @@ class FailedLoadModuleInitializationException(FailedLoadModuleException):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def debug_log(fu, enable = True):
|
def debug_log(fu, enable = True):
|
||||||
def new_fu(*args, **kwargs):
|
def new_dec(fu):
|
||||||
self = args[0]
|
def new_fu(*args, **kwargs):
|
||||||
log = self.log()
|
self = args[0]
|
||||||
skwargs = [','.join(['%s=%s' % (karg,repr(arg)) for karg, arg in kwargs])]
|
log = self.log()
|
||||||
sargs = [','.join([str(arg) for arg in args[1:]])] + '' if not skwargs else (',' + skwargs)
|
skwargs = ','.join(['%s=%s' % (karg,repr(arg)) for karg, arg in kwargs])
|
||||||
|
sargs = ','.join([str(arg) for arg in args[1:]]) + '' if not skwargs else (',' + str(skwargs))
|
||||||
|
|
||||||
|
call = "%s(%s)" % (fu.__name__, sargs)
|
||||||
|
log.debug(call)
|
||||||
|
res = fu(*args, **kwargs)
|
||||||
|
log.debug("%s -> %s", call, repr(res))
|
||||||
|
return res
|
||||||
|
return new_fu if enable else fu
|
||||||
|
return new_dec
|
||||||
|
|
||||||
|
|
||||||
call = "%s(%s)" % (fu.__name__, sargs)
|
|
||||||
log.debug()
|
|
||||||
res = fu(*args, **kwargs)
|
|
||||||
log.debug("%s -> %s", call, repr(res))
|
|
||||||
return res
|
|
||||||
return new_fu if enable else fu
|
|
||||||
|
|
||||||
debug_me = True
|
debug_me = True
|
||||||
|
|
||||||
@@ -80,7 +85,7 @@ class MumoManagerRemote(object):
|
|||||||
def getQueue(self):
|
def getQueue(self):
|
||||||
return self.__queue
|
return self.__queue
|
||||||
|
|
||||||
def subscribeMetaCallbacks(self, handler, servers = MumoManagerRemote.SERVERS_ALL):
|
def subscribeMetaCallbacks(self, handler, servers = SERVERS_ALL):
|
||||||
"""
|
"""
|
||||||
Subscribe to meta callbacks. Subscribes the given handler to the following
|
Subscribe to meta callbacks. Subscribes the given handler to the following
|
||||||
callbacks:
|
callbacks:
|
||||||
@@ -94,7 +99,7 @@ class MumoManagerRemote(object):
|
|||||||
"""
|
"""
|
||||||
return self.__master.subscribeMetaCallbacks(self.__queue, handler, servers)
|
return self.__master.subscribeMetaCallbacks(self.__queue, handler, servers)
|
||||||
|
|
||||||
def unsubscribeMetaCallbacks(self, handler, servers = MumoManagerRemote.SERVERS_ALL):
|
def unsubscribeMetaCallbacks(self, handler, servers = SERVERS_ALL):
|
||||||
"""
|
"""
|
||||||
Unsubscribe from meta callbacks. Unsubscribes the given handler from callbacks
|
Unsubscribe from meta callbacks. Unsubscribes the given handler from callbacks
|
||||||
for the given servers.
|
for the given servers.
|
||||||
@@ -105,7 +110,7 @@ class MumoManagerRemote(object):
|
|||||||
"""
|
"""
|
||||||
return self.__master.unscubscribeMetaCallbacks(self.__queue, handler, servers)
|
return self.__master.unscubscribeMetaCallbacks(self.__queue, handler, servers)
|
||||||
|
|
||||||
def subscribeServerCallbacks(self, handler, servers = MumoManagerRemote.SERVERS_ALL):
|
def subscribeServerCallbacks(self, handler, servers = SERVERS_ALL):
|
||||||
"""
|
"""
|
||||||
Subscribe to server callbacks. Subscribes the given handler to the following
|
Subscribe to server callbacks. Subscribes the given handler to the following
|
||||||
callbacks:
|
callbacks:
|
||||||
@@ -123,7 +128,7 @@ class MumoManagerRemote(object):
|
|||||||
"""
|
"""
|
||||||
return self.__master.subscribeServerCallbacks(self.__queue, handler, servers)
|
return self.__master.subscribeServerCallbacks(self.__queue, handler, servers)
|
||||||
|
|
||||||
def unsubscribeServerCallbacks(self, handler, servers = MumoManagerRemote.SERVERS_ALL):
|
def unsubscribeServerCallbacks(self, handler, servers = SERVERS_ALL):
|
||||||
"""
|
"""
|
||||||
Unsubscribe from server callbacks. Unsubscribes the given handler from callbacks
|
Unsubscribe from server callbacks. Unsubscribes the given handler from callbacks
|
||||||
for the given servers.
|
for the given servers.
|
||||||
@@ -134,7 +139,7 @@ class MumoManagerRemote(object):
|
|||||||
"""
|
"""
|
||||||
return self.__master.unsubscribeServerCallbacks(self.__queue, handler, servers)
|
return self.__master.unsubscribeServerCallbacks(self.__queue, handler, servers)
|
||||||
|
|
||||||
def subscribeContextCallbacks(self, handler, servers = MumoManagerRemote.SERVERS_ALL):
|
def subscribeContextCallbacks(self, handler, servers = SERVERS_ALL):
|
||||||
"""
|
"""
|
||||||
Subscribe to context callbacks. Subscribes the given handler to the following
|
Subscribe to context callbacks. Subscribes the given handler to the following
|
||||||
callbacks:
|
callbacks:
|
||||||
@@ -147,7 +152,7 @@ class MumoManagerRemote(object):
|
|||||||
"""
|
"""
|
||||||
return self.__master.subscribeContextCallbacks(self.__queue, handler, servers)
|
return self.__master.subscribeContextCallbacks(self.__queue, handler, servers)
|
||||||
|
|
||||||
def unsubscribeContextCallbacks(self, handler, servers = MumoManagerRemote.SERVERS_ALL):
|
def unsubscribeContextCallbacks(self, handler, servers = SERVERS_ALL):
|
||||||
"""
|
"""
|
||||||
Unsubscribe from context callbacks. Unsubscribes the given handler from callbacks
|
Unsubscribe from context callbacks. Unsubscribes the given handler from callbacks
|
||||||
for the given servers.
|
for the given servers.
|
||||||
@@ -163,7 +168,11 @@ class MumoManagerRemote(object):
|
|||||||
class MumoManager(Worker):
|
class MumoManager(Worker):
|
||||||
MAGIC_ALL = -1
|
MAGIC_ALL = -1
|
||||||
|
|
||||||
def __init__(self, cfg):
|
cfg_default = {'modules':{'mod_dir':(str, "modules/"),
|
||||||
|
'cfg_dir':(str, "modules-enabled/"),
|
||||||
|
'timeout':(int, 2)}}
|
||||||
|
|
||||||
|
def __init__(self, cfg = Config(default = cfg_default)):
|
||||||
Worker.__init__(self, "MumoManager")
|
Worker.__init__(self, "MumoManager")
|
||||||
self.queues = {} # {queue:module}
|
self.queues = {} # {queue:module}
|
||||||
self.modules = {} # {name:module}
|
self.modules = {} # {name:module}
|
||||||
@@ -285,7 +294,7 @@ class MumoManager(Worker):
|
|||||||
if not names:
|
if not names:
|
||||||
# If no names are given load all modules that have a configuration in the cfg_dir
|
# If no names are given load all modules that have a configuration in the cfg_dir
|
||||||
if not os.path.isdir(self.cfg.modules.cfg_dir):
|
if not os.path.isdir(self.cfg.modules.cfg_dir):
|
||||||
msg = "Module directory '%s' not found" % self.cfg.mumo.mod_dir
|
msg = "Module directory '%s' not found" % self.cfg.modules.mod_dir
|
||||||
self.log().error(msg)
|
self.log().error(msg)
|
||||||
raise FailedLoadModuleImportException(msg)
|
raise FailedLoadModuleImportException(msg)
|
||||||
|
|
||||||
@@ -356,12 +365,12 @@ class MumoManager(Worker):
|
|||||||
raise FailedLoadModuleConfigException(msg)
|
raise FailedLoadModuleConfigException(msg)
|
||||||
|
|
||||||
# Make sure the module directory is in our python path and exists
|
# Make sure the module directory is in our python path and exists
|
||||||
if not self.cfg.mumo.mod_dir in sys.path:
|
if not self.cfg.modules.mod_dir in sys.path:
|
||||||
if not os.path.isdir(self.cfg.mumo.mod_dir):
|
if not os.path.isdir(self.cfg.modules.mod_dir):
|
||||||
msg = "Module directory '%s' not found" % self.cfg.mumo.mod_dir
|
msg = "Module directory '%s' not found" % self.cfg.modules.mod_dir
|
||||||
log.error(msg)
|
log.error(msg)
|
||||||
raise FailedLoadModuleImportException(msg)
|
raise FailedLoadModuleImportException(msg)
|
||||||
sys.path.append(self.cfg.mumo.mod_dir)
|
sys.path.append(self.cfg.modules.mod_dir)
|
||||||
|
|
||||||
# Import the module and instanciate it
|
# Import the module and instanciate it
|
||||||
try:
|
try:
|
||||||
|
@@ -33,6 +33,8 @@ import unittest
|
|||||||
import Queue
|
import Queue
|
||||||
from mumo_manager import MumoManager, MumoManagerRemote
|
from mumo_manager import MumoManager, MumoManagerRemote
|
||||||
from mumo_module import MumoModule
|
from mumo_module import MumoModule
|
||||||
|
import logging
|
||||||
|
from threading import Event
|
||||||
|
|
||||||
|
|
||||||
class MumoManagerTest(unittest.TestCase):
|
class MumoManagerTest(unittest.TestCase):
|
||||||
@@ -40,43 +42,71 @@ class MumoManagerTest(unittest.TestCase):
|
|||||||
class MyModule(MumoModule):
|
class MyModule(MumoModule):
|
||||||
def __init__(self, name, manager, configuration = None):
|
def __init__(self, name, manager, configuration = None):
|
||||||
MumoModule.__init__(self, name, manager, configuration)
|
MumoModule.__init__(self, name, manager, configuration)
|
||||||
self.was_called = False
|
|
||||||
self.par1 = None
|
|
||||||
self.par2 = None
|
|
||||||
self.par3 = None
|
|
||||||
|
|
||||||
def last_call(self):
|
self.estarted = Event()
|
||||||
ret = (self.was_called, self.par1, self.par2, self.par3)
|
self.estopped = Event()
|
||||||
self.was_called = False
|
self.econnected = Event()
|
||||||
return ret
|
self.edisconnected = Event()
|
||||||
|
|
||||||
def call_me(self, par1, par2 = None, par3 = None):
|
def onStart(self):
|
||||||
self.was_called = True
|
self.estarted.set()
|
||||||
self.par1 = par1
|
|
||||||
self.par2 = par2
|
|
||||||
self.par3 = par3
|
|
||||||
|
|
||||||
self.man = MumoManager()
|
def onStop(self):
|
||||||
self.man.start()
|
self.estopped.set()
|
||||||
|
|
||||||
|
def connected(self):
|
||||||
|
self.econnected.set()
|
||||||
|
|
||||||
|
def disconnected(self):
|
||||||
|
self.edisconnected.set()
|
||||||
|
|
||||||
|
self.mymod = MyModule
|
||||||
|
|
||||||
class conf(object):
|
class conf(object):
|
||||||
pass # Dummy class
|
pass # Dummy class
|
||||||
|
|
||||||
cfg = conf()
|
self.cfg = conf()
|
||||||
cfg.test = 10
|
self.cfg.test = 10
|
||||||
|
|
||||||
self.mod = self.man.loadModuleCls("MyModule", MyModule, cfg)
|
#
|
||||||
self.man.startModules()
|
#--- Helpers for independent test env creation
|
||||||
|
#
|
||||||
|
def up(self):
|
||||||
|
man = MumoManager()
|
||||||
|
man.start()
|
||||||
|
|
||||||
|
mod = man.loadModuleCls("MyModule", self.mymod, self.cfg)
|
||||||
|
man.startModules()
|
||||||
|
|
||||||
|
return (man, mod)
|
||||||
|
|
||||||
|
def down(self, man, mod):
|
||||||
|
man.stopModules()
|
||||||
|
man.stop()
|
||||||
|
man.join(timeout=1)
|
||||||
|
|
||||||
|
#
|
||||||
|
#--- Tests
|
||||||
|
#
|
||||||
|
def testModuleStarted(self):
|
||||||
|
man, mod = self.up()
|
||||||
|
|
||||||
|
mod.estarted.wait(timeout=1)
|
||||||
|
assert(mod.estarted.is_set())
|
||||||
|
|
||||||
|
self.down(man, mod)
|
||||||
|
|
||||||
|
def testModuleStopStart(self):
|
||||||
|
man ,mod = self.up()
|
||||||
|
|
||||||
|
tos = ["MyModule"]
|
||||||
|
self.assertEquals(list(man.stopModules(tos).iterkeys()), tos)
|
||||||
|
mod.estopped.wait(timeout=1)
|
||||||
|
assert(mod.estopped.is_set())
|
||||||
|
|
||||||
|
self.down(man, mod)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.man.stopModules()
|
|
||||||
self.man.stop()
|
|
||||||
self.man.join(timeout=2)
|
|
||||||
|
|
||||||
|
|
||||||
def testName(self):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@@ -43,6 +43,8 @@ class MumoModule(Worker):
|
|||||||
# If we are passed a string expect a config file there
|
# If we are passed a string expect a config file there
|
||||||
if configuration:
|
if configuration:
|
||||||
self.__cfg = Config(configuration, self.default_config)
|
self.__cfg = Config(configuration, self.default_config)
|
||||||
|
elif self.default_config:
|
||||||
|
self.__cfg = Config(default = self.default_config)
|
||||||
else:
|
else:
|
||||||
self.__cfg = None
|
self.__cfg = None
|
||||||
else:
|
else:
|
||||||
|
@@ -44,6 +44,7 @@ mumo
|
|||||||
[modules]
|
[modules]
|
||||||
mod_dir = /usr/sbin/modules/
|
mod_dir = /usr/sbin/modules/
|
||||||
cfg_dir = /etc/modules-enabled/
|
cfg_dir = /etc/modules-enabled/
|
||||||
|
timeout = 2
|
||||||
|
|
||||||
[Ice]
|
[Ice]
|
||||||
ip = 127.0.0.1
|
ip = 127.0.0.1
|
||||||
|
Reference in New Issue
Block a user