diff options
| author | Barry Warsaw | 2008-02-27 01:26:18 -0500 |
|---|---|---|
| committer | Barry Warsaw | 2008-02-27 01:26:18 -0500 |
| commit | a1c73f6c305c7f74987d99855ba59d8fa823c253 (patch) | |
| tree | 65696889450862357c9e05c8e9a589f1bdc074ac /mailman/bin/testall.py | |
| parent | 3f31f8cce369529d177cfb5a7c66346ec1e12130 (diff) | |
| download | mailman-a1c73f6c305c7f74987d99855ba59d8fa823c253.tar.gz mailman-a1c73f6c305c7f74987d99855ba59d8fa823c253.tar.zst mailman-a1c73f6c305c7f74987d99855ba59d8fa823c253.zip | |
Diffstat (limited to 'mailman/bin/testall.py')
| -rw-r--r-- | mailman/bin/testall.py | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/mailman/bin/testall.py b/mailman/bin/testall.py new file mode 100644 index 000000000..9d50be111 --- /dev/null +++ b/mailman/bin/testall.py @@ -0,0 +1,244 @@ +# Copyright (C) 2001-2008 by the Free Software Foundation, Inc. +# +# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +"""Mailman unit test driver.""" + +from __future__ import with_statement + +import os +import re +import grp +import pwd +import sys +import shutil +import optparse +import tempfile +import unittest + +import mailman +import mailman.tests + +from mailman import Version +from mailman.configuration import config +from mailman.i18n import _ +from mailman.initialize import initialize_1, initialize_2 + +basedir = None + + + +def v_callback(option, opt, value, parser): + if opt in ('-q', '--quiet'): + delta = -1 + elif opt in ('-v', '--verbose'): + delta = 1 + else: + raise AssertionError('Unexpected option: %s' % opt) + dest = getattr(parser.values, option.dest) + setattr(parser.values, option.dest, max(0, dest + delta)) + + +def parseargs(): + parser = optparse.OptionParser(version=Version.MAILMAN_VERSION, + usage=_("""\ +%prog [options] [tests] + +Run the Mailman unit test suite. 'tests' is one or more Python regular +expressions matching only the tests you want to run. Prefix the regular +expression with '!' to specify a negative test.""")) + parser.set_defaults(verbosity=2) + parser.add_option('-v', '--verbose', + action='callback', callback=v_callback, + dest='verbosity', help=_("""\ +Increase verbosity by 1, which defaults to %default. Use -q to reduce +verbosity. -v and -q options accumulate.""")) + parser.add_option('-q', '--quiet', + action='callback', callback=v_callback, + dest='verbosity', help=_("""\ +Reduce verbosity by 1 (but not below 0).""")) + parser.add_option('-e', '--stderr', + default=False, action='store_true', + help=_('Propagate log errors to stderr.')) + parser.add_option('-c', '--coverage', + default=False, action='store_true', + help=_('Enable code coverage.')) + opts, args = parser.parse_args() + return parser, opts, args + + + +def search(): + testnames = [] + # Walk the entire tree from the current base directory. Look for modules + # that start with 'test_'. Calculate the full module path name to this + # module, append 'test_suite' and add that to testnames. This way, we run + # all the suites defined in the test_suite() function inside all test + # modules. + for dirpath, dirnames, filenames in os.walk(basedir): + for fn in filenames: + if fn.startswith('test_') and fn.endswith('.py'): + # Start with full path + path = os.path.join(dirpath, fn) + # Convert the file path to a module path. First, we must make + # the file path relative to the root directory. Then strip + # off the trailing .py + path = path[len(basedir)+1:-3] + # Convert slashes to dots + modpath = path.replace(os.sep, '.') + '.test_suite' + testnames.append('mailman.' + modpath) + return testnames + + +def match(pat, name): + if not pat: + return True + if pat.startswith('!'): + # Negative test + return re.search(pat[1:], name) is None + else: + # Positive test + return re.search(pat, name) is not None + + +def filter_tests(suite, patterns): + if '.' in patterns: + return suite + new = unittest.TestSuite() + for test in suite._tests: + if isinstance(test, unittest.TestCase): + # Get the fill test name: package.module.class.method + name = test.id() + for pat in patterns: + if match(pat, name): + new.addTest(test) + break + else: + filtered = filter_tests(test, patterns) + if filtered: + new.addTest(filtered) + return new + + +def suite(patterns=None): + if patterns is None: + patterns = '.' + loader = unittest.TestLoader() + # Search for all tests that match the given patterns + testnames = search() + suite = loader.loadTestsFromNames(testnames) + return filter_tests(suite, patterns) + + + +def main(): + global basedir + + parser, opts, args = parseargs() + if not args: + args = ['.'] + + # Store the options some place that other code can get to it. + config.opts = opts + + # Turn on code coverage if selected. + if opts.coverage: + try: + import coverage + except ImportError: + opts.coverage = False + else: + coverage.start() + + # Set up the testing configuration file both for this process, and for all + # sub-processes testing will spawn (e.g. the qrunners). + # + # Calculate a temporary VAR_DIR directory so that run-time artifacts of + # the tests won't tread on the installation's data. This also makes it + # easier to clean up after the tests are done, and insures isolation of + # test suite runs. + cfg_in = os.path.join(os.path.dirname(mailman.tests.__file__), + 'testing.cfg.in') + fd, cfg_out = tempfile.mkstemp(suffix='.cfg') + os.close(fd) + shutil.copyfile(cfg_in, cfg_out) + + var_dir = tempfile.mkdtemp() + if opts.verbosity > 2: + print 'VAR_DIR :', var_dir + print 'config file:', cfg_out + + user_id = os.getuid() + user_name = pwd.getpwuid(user_id).pw_name + group_id = os.getgid() + group_name = grp.getgrgid(group_id).gr_name + + try: + with open(cfg_out, 'a') as fp: + print >> fp, 'VAR_DIR = "%s"' % var_dir + print >> fp, 'MAILMAN_USER = "%s"' % user_name + print >> fp, 'MAILMAN_UID = %d' % user_id + print >> fp, 'MAILMAN_GROUP = "%s"' % group_name + print >> fp, 'MAILMAN_GID = %d' % group_id + print >> fp, "LANGUAGES = 'en'" + + initialize_1(cfg_out, propagate_logs=opts.stderr) + mailman_uid = pwd.getpwnam(config.MAILMAN_USER).pw_uid + mailman_gid = grp.getgrnam(config.MAILMAN_GROUP).gr_gid + os.chmod(cfg_out, 0660) + os.chown(cfg_out, mailman_uid, mailman_gid) + + # Create an empty SQLite database file with the proper permissions and + # calculate the SQLAlchemy engine url to this database file. + fd, config.dbfile = tempfile.mkstemp(dir=config.DATA_DIR, suffix='.db') + os.close(fd) + os.chmod(config.dbfile, 0660) + os.chown(config.dbfile, mailman_uid, mailman_gid) + + # Patch ups + test_engine_url = 'sqlite:///' + config.dbfile + config.SQLALCHEMY_ENGINE_URL = test_engine_url + + # Write this to the config file so subprocesses share the same testing + # database file. + with open(cfg_out, 'a') as fp: + print >> fp, 'SQLALCHEMY_ENGINE_URL = "%s"' % test_engine_url + + # With -vvv, turn on engine debugging. + initialize_2(opts.verbosity > 3) + + # Run the tests + basedir = os.path.dirname(mailman.__file__) + runner = unittest.TextTestRunner(verbosity=opts.verbosity) + results = runner.run(suite(args)) + finally: + os.remove(cfg_out) + shutil.rmtree(var_dir) + + # Turn off coverage and print a report + if opts.coverage: + coverage.stop() + modules = [module for name, module in sys.modules.items() + if module + and name is not None + and name.split('.')[0] == 'mailman'] + coverage.report(modules) + sys.exit(bool(results.failures or results.errors)) + + + +if __name__ == '__main__': + main() |
