Create component runner
- JCLRunner handle configuration file and command line arguments to setup a JCL component darcs-hash:20070518143255-86b55-f5dfd32edeb34c9d30b85a1dd05a12c6a8423806.gz
This commit is contained in:
34
src/jcl.py
Normal file
34
src/jcl.py
Normal file
@@ -0,0 +1,34 @@
|
||||
##
|
||||
## jcl.py
|
||||
## Login : David Rousselie <dax@happycoders.org>
|
||||
## Started on Fri May 18 15:19:20 2007 David Rousselie
|
||||
## $Id$
|
||||
##
|
||||
## Copyright (C) 2007 David Rousselie
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 2 of the License, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##
|
||||
|
||||
import sys
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf-8')
|
||||
del sys.setdefaultencoding
|
||||
|
||||
import jcl
|
||||
from jcl.runner import JCLRunner
|
||||
|
||||
if __name__ == '__main__':
|
||||
runner = JCLRunner("JCL", jcl.version)
|
||||
runner.configure()
|
||||
runner.run()
|
||||
@@ -1,2 +1,5 @@
|
||||
"""JCL module"""
|
||||
__revision__ = ""
|
||||
|
||||
version = "0.1.0"
|
||||
|
||||
|
||||
@@ -62,7 +62,6 @@ VERSION = "0.1"
|
||||
###############################################################################
|
||||
class JCLComponent(Component, object):
|
||||
"""Implement default JCL component behavior:
|
||||
- regular interval behavior
|
||||
- Jabber register process (add, delete, update accounts)
|
||||
- Jabber presence handling
|
||||
- passwork request at login
|
||||
|
||||
208
src/jcl/runner.py
Normal file
208
src/jcl/runner.py
Normal file
@@ -0,0 +1,208 @@
|
||||
##
|
||||
## runner.py
|
||||
## Login : David Rousselie <dax@happycoders.org>
|
||||
## Started on Thu May 17 22:02:08 2007 David Rousselie
|
||||
## $Id$
|
||||
##
|
||||
## Copyright (C) 2007 David Rousselie
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 2 of the License, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from ConfigParser import ConfigParser
|
||||
from getopt import gnu_getopt
|
||||
|
||||
from sqlobject import *
|
||||
|
||||
from jcl.model import account
|
||||
from jcl.model.account import Account, PresenceAccount
|
||||
|
||||
class JCLRunner(object):
|
||||
def __init__(self, component_name, component_version):
|
||||
"""
|
||||
options: list of tuples:
|
||||
- short_opt: same as getopt
|
||||
- long_opt: same as getopt
|
||||
"""
|
||||
self.component_name = component_name
|
||||
self.component_version = component_version
|
||||
self.config_file = None
|
||||
self.server = "localhost"
|
||||
self.port = 5347
|
||||
self.secret = "secret"
|
||||
self.service_jid = "jcl.localhost"
|
||||
self.language = "en"
|
||||
self.db_url = "sqlite:///var/spool/jabber/jcl.db"
|
||||
self.pid_file = "/var/run/jabber/jcl.pid"
|
||||
self.options = [("c:", "config-file=", None, \
|
||||
" FILE\t\t\t\tConfiguration file to use", \
|
||||
lambda arg: self.set_attr("config_file", arg)), \
|
||||
("S:", "server=", "jabber", \
|
||||
" SERVER_ADDRESS\t\t\tAddress of the Jabber server", \
|
||||
lambda arg: self.set_attr("server", arg)), \
|
||||
("P:", "port=", "jabber", \
|
||||
" PORT\t\t\t\t\tPort of the Jabber server to connect the component", \
|
||||
lambda arg: self.set_attr("port", int(arg))), \
|
||||
("s:", "secret=", "jabber", \
|
||||
" SECRET\t\t\t\tComponent password to connect to the Jabber server", \
|
||||
lambda arg: self.set_attr("secret", arg)), \
|
||||
("j:", "service-jid=", "jabber", \
|
||||
" JID\t\t\t\tJID of the component", \
|
||||
lambda arg: self.set_attr("service_jid", arg)), \
|
||||
("l:", "language=", "jabber", \
|
||||
" LANG\t\t\t\tDefault Language of the component", \
|
||||
lambda arg: self.set_attr("language", arg)), \
|
||||
("u:", "db-url=", "db", \
|
||||
" URL\t\t\t\tDatabase URL", \
|
||||
lambda arg: self.set_attr("db_url", arg)), \
|
||||
("p:", "pid-file=", "component", \
|
||||
" FILE\t\t\t\tPath of the PID file", \
|
||||
lambda arg: self.set_attr("pid_file", arg)), \
|
||||
("d", "debug", None, \
|
||||
"\t\t\t\t\tEnable debug traces", \
|
||||
lambda arg: self.set_attr("debug", True)), \
|
||||
("h", "help", None, \
|
||||
"\t\t\t\t\tThis help", \
|
||||
lambda arg: self.print_help())]
|
||||
self.logger = logging.getLogger()
|
||||
self.logger.addHandler(logging.StreamHandler())
|
||||
self.__debug = False
|
||||
|
||||
def set_attr(self, attr, value):
|
||||
setattr(self, attr, value)
|
||||
|
||||
def __configure_commandline_args(self, shortopts, longopts, cleanopts):
|
||||
(opts, args) = gnu_getopt(sys.argv[1:], shortopts, longopts)
|
||||
commandline_args = {}
|
||||
for (arg, value) in opts:
|
||||
clean_arg = arg.lstrip('-')
|
||||
if cleanopts.has_key(clean_arg):
|
||||
commandline_args[clean_arg] = value
|
||||
return commandline_args
|
||||
|
||||
def __apply_commandline_args(self, commandline_args, cleanopts):
|
||||
for arg in commandline_args:
|
||||
value = commandline_args[arg]
|
||||
self.logger.debug("Applying argument " + arg + " = " + \
|
||||
value)
|
||||
cleanopts[arg][1](value)
|
||||
|
||||
def __apply_configfile(self, commandline_args, cleanopts):
|
||||
if commandline_args.has_key("config_file"):
|
||||
self.config_file = commandline_args["config_file"]
|
||||
elif commandline_args.has_key("c"):
|
||||
self.config_file = commandline_args["c"]
|
||||
if self.config_file is not None:
|
||||
self.config = ConfigParser()
|
||||
self.logger.debug("Loading config file " + self.config_file)
|
||||
read_file = self.config.read(self.config_file)
|
||||
if read_file == []:
|
||||
raise IOError(2, "No such file or directory", str(self.config_file))
|
||||
for opt in cleanopts:
|
||||
if len(opt) > 1:
|
||||
(section, set_func) = cleanopts[opt]
|
||||
if section is not None:
|
||||
attr = opt.replace("-", "_")
|
||||
config_property = self.config.get(section, attr)
|
||||
self.logger.debug("Setting " + attr + " = " + \
|
||||
config_property + \
|
||||
" from configuration file " + \
|
||||
self.config_file)
|
||||
set_func(config_property)
|
||||
|
||||
def configure(self):
|
||||
"""Apply configuration from command line and configuration file.
|
||||
command line arguments override configuration file properties.
|
||||
"""
|
||||
shortopts = ""
|
||||
longopts = []
|
||||
cleanopts = {}
|
||||
for option in self.options:
|
||||
shortopts += option[0]
|
||||
longopts += [option[1]]
|
||||
cleanopts[option[0][0]] = (option[2], option[4])
|
||||
if option[1][-1:] == '=':
|
||||
cleanopts[option[1][:-1]] = (option[2], option[4])
|
||||
else:
|
||||
cleanopts[option[1]] = (option[2], option[4])
|
||||
|
||||
commandline_args = self.__configure_commandline_args(shortopts, longopts, cleanopts)
|
||||
if commandline_args.has_key("debug") or commandline_args.has_key("d"):
|
||||
self.debug = True
|
||||
self.__apply_configfile(commandline_args, cleanopts)
|
||||
self.__apply_commandline_args(commandline_args, cleanopts)
|
||||
|
||||
def _get_help(self):
|
||||
help = self.component_name + " v" + self.component_version + " help:\n"
|
||||
for option in self.options:
|
||||
if option[1][-1:] == '=':
|
||||
long_option = option[1][:-1]
|
||||
else:
|
||||
long_option = option[1]
|
||||
help += "\t-" + option[0][0] + ", --" + long_option + option[3] + "\n"
|
||||
return help
|
||||
|
||||
def print_help(self):
|
||||
print self._get_help()
|
||||
sys.exit(0)
|
||||
|
||||
def get_debug(self):
|
||||
return self.__debug
|
||||
|
||||
def set_debug(self, value):
|
||||
self.__debug = value
|
||||
if self.__debug:
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
else:
|
||||
self.logger.setLevel(logging.CRITICAL)
|
||||
|
||||
debug = property(get_debug, set_debug)
|
||||
|
||||
|
||||
def setup_db(self):
|
||||
Account.createTable(ifNotExists = True)
|
||||
PresenceAccount.createTable(ifNotExists = True)
|
||||
|
||||
def setup_pidfile(self):
|
||||
pidfile = open(self.pid_file, "w")
|
||||
pidfile.write(str(os.getpid()))
|
||||
pidfile.close()
|
||||
|
||||
def _run(self, run_func):
|
||||
try:
|
||||
self.setup_pidfile()
|
||||
account.hub.threadConnection = connectionForURI(self.db_url)
|
||||
self.setup_db()
|
||||
del account.hub.threadConnection
|
||||
self.logger.debug(self.component_name + " v" + \
|
||||
self.component_version + " is starting ...")
|
||||
run_func()
|
||||
self.logger.debug(self.component_name + " is exiting")
|
||||
finally:
|
||||
os.remove(self.pid_file)
|
||||
|
||||
def run(self):
|
||||
def run_func():
|
||||
component = JCLComponent(jid = self.service_jid, \
|
||||
secret = self.secret, \
|
||||
server = self.server, \
|
||||
port = self.port, \
|
||||
db_connection_str = self.db_url, \
|
||||
lang = Lang(self.language))
|
||||
component.run()
|
||||
self._run(run_func)
|
||||
|
||||
@@ -3,13 +3,14 @@ __revision__ = ""
|
||||
|
||||
import unittest
|
||||
|
||||
from jcl.tests import lang
|
||||
from jcl.tests import lang, runner
|
||||
from jcl.jabber import tests as jabber
|
||||
from jcl.model import tests as model
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(lang.suite())
|
||||
suite.addTest(runner.suite())
|
||||
suite.addTest(jabber.suite())
|
||||
suite.addTest(model.suite())
|
||||
return suite
|
||||
|
||||
21
src/jcl/tests/jcl.conf
Normal file
21
src/jcl/tests/jcl.conf
Normal file
@@ -0,0 +1,21 @@
|
||||
[jabber]
|
||||
server: test_localhost
|
||||
port: 42
|
||||
secret: test_secret
|
||||
service_jid: test_jcl.localhost
|
||||
#supported language: en, fr (See src/jmc/lang.py to add more)
|
||||
language: test_en
|
||||
|
||||
[db]
|
||||
#type: mysql
|
||||
type: test_sqlite
|
||||
#host: root@localhost
|
||||
host: root@localhost
|
||||
name: /var/spool/jabber/test_jcl.db
|
||||
#url: %(type)%(host)%(name)?debug=1&debugThreading=1
|
||||
db_url: %(type)s://%(host)s%(name)s
|
||||
|
||||
[component]
|
||||
pid_file: /var/run/jabber/test_jcl.pid
|
||||
|
||||
|
||||
146
src/jcl/tests/runner.py
Normal file
146
src/jcl/tests/runner.py
Normal file
@@ -0,0 +1,146 @@
|
||||
##
|
||||
## runner.py
|
||||
## Login : David Rousselie <dax@happycoders.org>
|
||||
## Started on Fri May 18 13:43:37 2007 David Rousselie
|
||||
## $Id$
|
||||
##
|
||||
## Copyright (C) 2007 David Rousselie
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 2 of the License, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##
|
||||
|
||||
import unittest
|
||||
import sys
|
||||
import os
|
||||
|
||||
from sqlobject import *
|
||||
|
||||
import jcl
|
||||
from jcl.runner import JCLRunner
|
||||
|
||||
from jcl.model import account
|
||||
from jcl.model.account import Account, PresenceAccount
|
||||
|
||||
if sys.platform == "win32":
|
||||
DB_PATH = "/c|/temp/test.db"
|
||||
else:
|
||||
DB_PATH = "/tmp/test.db"
|
||||
DB_URL = "sqlite://" + DB_PATH# + "?debug=1&debugThreading=1"
|
||||
|
||||
class JCLRunner_TestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.runner = JCLRunner("JCL", jcl.version)
|
||||
|
||||
def tearDown(self):
|
||||
self.runner = None
|
||||
sys.argv = [""]
|
||||
|
||||
def test_configure_default(self):
|
||||
self.runner.configure()
|
||||
self.assertEquals(self.runner.config_file, None)
|
||||
self.assertEquals(self.runner.server, "localhost")
|
||||
self.assertEquals(self.runner.port, 5347)
|
||||
self.assertEquals(self.runner.secret, "secret")
|
||||
self.assertEquals(self.runner.service_jid, "jcl.localhost")
|
||||
self.assertEquals(self.runner.language, "en")
|
||||
self.assertEquals(self.runner.db_url, "sqlite:///var/spool/jabber/jcl.db")
|
||||
self.assertEquals(self.runner.pid_file, "/var/run/jabber/jcl.pid")
|
||||
self.assertFalse(self.runner.debug)
|
||||
|
||||
def test_configure_configfile(self):
|
||||
self.runner.config_file = "src/jcl/tests/jcl.conf"
|
||||
self.runner.configure()
|
||||
self.assertEquals(self.runner.server, "test_localhost")
|
||||
self.assertEquals(self.runner.port, 42)
|
||||
self.assertEquals(self.runner.secret, "test_secret")
|
||||
self.assertEquals(self.runner.service_jid, "test_jcl.localhost")
|
||||
self.assertEquals(self.runner.language, "test_en")
|
||||
self.assertEquals(self.runner.db_url, "test_sqlite://root@localhost/var/spool/jabber/test_jcl.db")
|
||||
self.assertEquals(self.runner.pid_file, "/var/run/jabber/test_jcl.pid")
|
||||
self.assertFalse(self.runner.debug)
|
||||
|
||||
def test_configure_commandline_shortopt(self):
|
||||
sys.argv = ["", "-c", "src/jcl/tests/jcl.conf", \
|
||||
"-S", "test2_localhost", \
|
||||
"-P", "43", \
|
||||
"-s", "test2_secret", \
|
||||
"-j", "test2_jcl.localhost", \
|
||||
"-l", "test2_en", \
|
||||
"-u", "sqlite:///tmp/test_jcl.db", \
|
||||
"-p", "/tmp/test_jcl.pid"]
|
||||
self.runner.configure()
|
||||
self.assertEquals(self.runner.server, "test2_localhost")
|
||||
self.assertEquals(self.runner.port, 43)
|
||||
self.assertEquals(self.runner.secret, "test2_secret")
|
||||
self.assertEquals(self.runner.service_jid, "test2_jcl.localhost")
|
||||
self.assertEquals(self.runner.language, "test2_en")
|
||||
self.assertEquals(self.runner.db_url, "sqlite:///tmp/test_jcl.db")
|
||||
self.assertEquals(self.runner.pid_file, "/tmp/test_jcl.pid")
|
||||
self.assertFalse(self.runner.debug)
|
||||
|
||||
def test_configure_commandline_longopt(self):
|
||||
sys.argv = ["", "--config-file", "src/jcl/tests/jcl.conf", \
|
||||
"--server", "test2_localhost", \
|
||||
"--port", "43", \
|
||||
"--secret", "test2_secret", \
|
||||
"--service-jid", "test2_jcl.localhost", \
|
||||
"--language", "test2_en", \
|
||||
"--db-url", "sqlite:///tmp/test_jcl.db", \
|
||||
"--pid-file", "/tmp/test_jcl.pid"]
|
||||
self.runner.configure()
|
||||
self.assertEquals(self.runner.server, "test2_localhost")
|
||||
self.assertEquals(self.runner.port, 43)
|
||||
self.assertEquals(self.runner.secret, "test2_secret")
|
||||
self.assertEquals(self.runner.service_jid, "test2_jcl.localhost")
|
||||
self.assertEquals(self.runner.language, "test2_en")
|
||||
self.assertEquals(self.runner.db_url, "sqlite:///tmp/test_jcl.db")
|
||||
self.assertEquals(self.runner.pid_file, "/tmp/test_jcl.pid")
|
||||
self.assertFalse(self.runner.debug)
|
||||
|
||||
def test_setup_pidfile(self):
|
||||
try:
|
||||
self.runner.pid_file = "/tmp/jcl.pid"
|
||||
self.runner.setup_pidfile()
|
||||
pidfile = open("/tmp/jcl.pid", "r")
|
||||
pid = int(pidfile.read())
|
||||
pidfile.close()
|
||||
self.assertEquals(pid, os.getpid())
|
||||
finally:
|
||||
os.remove("/tmp/jcl.pid")
|
||||
|
||||
def test__run(self):
|
||||
self.runner.pid_file = "/tmp/jcl.pid"
|
||||
self.runner.db_url = DB_URL
|
||||
def do_nothing():
|
||||
pass
|
||||
self.runner._run(do_nothing)
|
||||
account.hub.threadConnection = connectionForURI(self.runner.db_url)
|
||||
# dropTable should succeed because tables should exist
|
||||
Account.dropTable()
|
||||
PresenceAccount.dropTable()
|
||||
del account.hub.threadConnection
|
||||
os.unlink(DB_PATH)
|
||||
self.assertFalse(os.access("/tmp/jcl.pid", os.F_OK))
|
||||
|
||||
def test__get_help(self):
|
||||
self.assertNotEquals(self.runner._get_help(), None)
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(JCLRunner_TestCase, 'test'))
|
||||
return suite
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
||||
Reference in New Issue
Block a user