diff --git a/config.py b/config.py index 6330c4e..3b87c53 100644 --- a/config.py +++ b/config.py @@ -37,26 +37,36 @@ class Config(object): """ def __init__(self, filename = None, default = None): - if not filename or not default: return - cfg = ConfigParser.ConfigParser() - cfg.optionxform = str - cfg.read(filename) + if (filename and not default) or \ + (not filename and not default): return + + if filename: + cfg = ConfigParser.ConfigParser() + cfg.optionxform = str + cfg.read(filename) for h,v in default.iteritems(): if not v: # Output this whole section as a list of raw key/value tuples - try: - self.__dict__[h] = cfg.items(h) - except ConfigParser.NoSectionError: + if not filename: self.__dict__[h] = [] + else: + try: + self.__dict__[h] = cfg.items(h) + except ConfigParser.NoSectionError: + self.__dict__[h] = [] else: self.__dict__[h] = Config() for name, val in v.iteritems(): conv, vdefault = val - try: - self.__dict__[h].__dict__[name] = conv(cfg.get(h, name)) - except (ValueError, ConfigParser.NoSectionError, ConfigParser.NoOptionError): + + if not filename: 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): """Helper function to convert strings from the config to bool""" diff --git a/config_test.py b/config_test.py index 725dc4c..0f6fe2d 100644 --- a/config_test.py +++ b/config_test.py @@ -104,6 +104,12 @@ testfallbacknum = asdas assert(cfg.somethingelse.bla == "test") finally: 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__": diff --git a/mumo_manager.py b/mumo_manager.py index d67dea3..644e7db 100644 --- a/mumo_manager.py +++ b/mumo_manager.py @@ -31,6 +31,7 @@ import Queue from worker import Worker, local_thread, local_thread_blocking +from config import Config import sys import os @@ -47,18 +48,22 @@ class FailedLoadModuleInitializationException(FailedLoadModuleException): pass def debug_log(fu, enable = True): - def new_fu(*args, **kwargs): - self = args[0] - log = self.log() - 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 (',' + skwargs) - - 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 + def new_dec(fu): + def new_fu(*args, **kwargs): + self = args[0] + log = self.log() + 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 + + debug_me = True @@ -80,7 +85,7 @@ class MumoManagerRemote(object): def getQueue(self): 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 callbacks: @@ -94,7 +99,7 @@ class MumoManagerRemote(object): """ 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 for the given servers. @@ -105,7 +110,7 @@ class MumoManagerRemote(object): """ 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 callbacks: @@ -123,7 +128,7 @@ class MumoManagerRemote(object): """ 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 for the given servers. @@ -134,7 +139,7 @@ class MumoManagerRemote(object): """ 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 callbacks: @@ -147,7 +152,7 @@ class MumoManagerRemote(object): """ 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 for the given servers. @@ -162,8 +167,12 @@ class MumoManagerRemote(object): class MumoManager(Worker): MAGIC_ALL = -1 + + cfg_default = {'modules':{'mod_dir':(str, "modules/"), + 'cfg_dir':(str, "modules-enabled/"), + 'timeout':(int, 2)}} - def __init__(self, cfg): + def __init__(self, cfg = Config(default = cfg_default)): Worker.__init__(self, "MumoManager") self.queues = {} # {queue:module} self.modules = {} # {name:module} @@ -285,7 +294,7 @@ class MumoManager(Worker): if not names: # 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): - 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) raise FailedLoadModuleImportException(msg) @@ -356,12 +365,12 @@ class MumoManager(Worker): raise FailedLoadModuleConfigException(msg) # Make sure the module directory is in our python path and exists - if not self.cfg.mumo.mod_dir in sys.path: - if not os.path.isdir(self.cfg.mumo.mod_dir): - msg = "Module directory '%s' not found" % self.cfg.mumo.mod_dir + if not self.cfg.modules.mod_dir in sys.path: + if not os.path.isdir(self.cfg.modules.mod_dir): + msg = "Module directory '%s' not found" % self.cfg.modules.mod_dir log.error(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 try: diff --git a/mumo_manager_test.py b/mumo_manager_test.py index 939142a..07a89f9 100644 --- a/mumo_manager_test.py +++ b/mumo_manager_test.py @@ -33,6 +33,8 @@ import unittest import Queue from mumo_manager import MumoManager, MumoManagerRemote from mumo_module import MumoModule +import logging +from threading import Event class MumoManagerTest(unittest.TestCase): @@ -40,45 +42,73 @@ class MumoManagerTest(unittest.TestCase): class MyModule(MumoModule): def __init__(self, name, manager, configuration = None): MumoModule.__init__(self, name, manager, configuration) - self.was_called = False - self.par1 = None - self.par2 = None - self.par3 = None - def last_call(self): - ret = (self.was_called, self.par1, self.par2, self.par3) - self.was_called = False - return ret - - def call_me(self, par1, par2 = None, par3 = None): - self.was_called = True - self.par1 = par1 - self.par2 = par2 - self.par3 = par3 - - self.man = MumoManager() - self.man.start() + self.estarted = Event() + self.estopped = Event() + self.econnected = Event() + self.edisconnected = Event() + + def onStart(self): + self.estarted.set() + + def onStop(self): + self.estopped.set() + + def connected(self): + self.econnected.set() + + def disconnected(self): + self.edisconnected.set() + self.mymod = MyModule + class conf(object): pass # Dummy class - cfg = conf() - cfg.test = 10 - - self.mod = self.man.loadModuleCls("MyModule", MyModule, cfg) - self.man.startModules() - + self.cfg = conf() + self.cfg.test = 10 + # + #--- 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): - self.man.stopModules() - self.man.stop() - self.man.join(timeout=2) - - - def testName(self): pass - + if __name__ == "__main__": #import sys;sys.argv = ['', 'Test.testName'] diff --git a/mumo_module.py b/mumo_module.py index b753c24..1956971 100644 --- a/mumo_module.py +++ b/mumo_module.py @@ -43,6 +43,8 @@ class MumoModule(Worker): # If we are passed a string expect a config file there if configuration: self.__cfg = Config(configuration, self.default_config) + elif self.default_config: + self.__cfg = Config(default = self.default_config) else: self.__cfg = None else: diff --git a/sketches.txt b/sketches.txt index c912352..674a39e 100644 --- a/sketches.txt +++ b/sketches.txt @@ -44,6 +44,7 @@ mumo [modules] mod_dir = /usr/sbin/modules/ cfg_dir = /etc/modules-enabled/ +timeout = 2 [Ice] ip = 127.0.0.1