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:
21
conf/jcl.conf
Normal file
21
conf/jcl.conf
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[jabber]
|
||||||
|
server: localhost
|
||||||
|
port: 5347
|
||||||
|
secret: secret
|
||||||
|
service_jid: jcl.localhost
|
||||||
|
#supported language: en, fr (See src/jcl/lang.py to add more)
|
||||||
|
language: en
|
||||||
|
|
||||||
|
[db]
|
||||||
|
#type: mysql
|
||||||
|
type: sqlite
|
||||||
|
#host: root@localhost
|
||||||
|
host:
|
||||||
|
name: /var/spool/jabber/jcl.db
|
||||||
|
#url: %(type)%(host)%(name)?debug=1&debugThreading=1
|
||||||
|
db_url: %(type)s://%(host)s%(name)s
|
||||||
|
|
||||||
|
[component]
|
||||||
|
pid_file: /var/run/jabber/jcl.pid
|
||||||
|
|
||||||
|
|
||||||
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"""
|
"""JCL module"""
|
||||||
__revision__ = ""
|
__revision__ = ""
|
||||||
|
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ VERSION = "0.1"
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
class JCLComponent(Component, object):
|
class JCLComponent(Component, object):
|
||||||
"""Implement default JCL component behavior:
|
"""Implement default JCL component behavior:
|
||||||
- regular interval behavior
|
|
||||||
- Jabber register process (add, delete, update accounts)
|
- Jabber register process (add, delete, update accounts)
|
||||||
- Jabber presence handling
|
- Jabber presence handling
|
||||||
- passwork request at login
|
- 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
|
import unittest
|
||||||
|
|
||||||
from jcl.tests import lang
|
from jcl.tests import lang, runner
|
||||||
from jcl.jabber import tests as jabber
|
from jcl.jabber import tests as jabber
|
||||||
from jcl.model import tests as model
|
from jcl.model import tests as model
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
suite = unittest.TestSuite()
|
suite = unittest.TestSuite()
|
||||||
suite.addTest(lang.suite())
|
suite.addTest(lang.suite())
|
||||||
|
suite.addTest(runner.suite())
|
||||||
suite.addTest(jabber.suite())
|
suite.addTest(jabber.suite())
|
||||||
suite.addTest(model.suite())
|
suite.addTest(model.suite())
|
||||||
return 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