#!/usr/bin/env python ### # Copyright (c) 2002-2005, Jeremiah Fincher # Copyright (c) 2011, James McCoy # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions, and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the author of this software nor the name of # contributors to this software may be used to endorse or promote products # derived from this software without specific prior written consent. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. ### import os import sys import time import shutil started = time.time() import supybot import logging import traceback # We need to do this before we import conf. if not os.path.exists('test-conf'): os.mkdir('test-conf') registryFilename = os.path.join('test-conf', 'test.conf') fd = open(registryFilename, 'w') fd.write(""" supybot.directories.data: test-data supybot.directories.conf: test-conf supybot.directories.log: test-logs supybot.reply.whenNotCommand: True supybot.log.stdout: False supybot.log.level: DEBUG supybot.log.format: %(levelname)s %(message)s supybot.log.plugins.individualLogfiles: False supybot.protocols.irc.throttleTime: 0 supybot.reply.whenAddressedBy.chars: @ supybot.networks.test.server: should.not.need.this supybot.nick: test supybot.databases.users.allowUnregistration: True """) fd.close() import supybot.registry as registry registry.open_registry(registryFilename) import supybot.log as log import supybot.conf as conf conf.allowEval = True conf.supybot.flush.setValue(False) import re import sys import glob import atexit import os.path import unittest import supybot.utils as utils import supybot.world as world import supybot.callbacks as callbacks world.startedAt = started import logging class TestLogFilter(logging.Filter): bads = [ 'No callbacks in', 'Invalid channel database', 'Exact error', 'Invalid user dictionary', 'because of noFlush', 'Queuing NICK', 'Queuing USER', 'IgnoresDB.reload failed', 'Starting log for', 'Irc object for test dying', 'Last Irc,', ] def filter(self, record): for bad in self.bads: if bad in record.msg: return False return True log._logger.addFilter(TestLogFilter()) class path(str): """A class to represent platform-independent paths.""" _r = re.compile(r'[\\/]') def __hash__(self): return reduce(lambda h, s: h ^ hash(s), self._r.split(self), 0) def __eq__(self, other): return self._r.split(self) == self._r.split(other) if __name__ == '__main__': import glob import os.path import optparse import supybot.test as test import supybot.plugin as plugin parser = optparse.OptionParser(usage='Usage: %prog [options] [plugins]', version='Supybot %s' % conf.version) parser.add_option('-c', '--clean', action='store_true', default=False, dest='clean', help='Cleans the various data/conf/logs' 'directories before running tests.') parser.add_option('-t', '--timeout', action='store', type='float', dest='timeout', help='Sets the timeout, in seconds, for tests to return ' 'responses.') parser.add_option('-v', '--verbose', action='store_true', default=False, help='Sets the verbose flag, logging extra information ' 'about each test that runs.') parser.add_option('', '--no-network', action='store_true', default=False, dest='nonetwork', help='Causes the network-based tests ' 'not to run.') parser.add_option('', '--trace', action='store_true', default=False, help='Traces all calls made. Unless you\'re really in ' 'a pinch, you probably shouldn\'t do this; it results ' 'in copious amounts of output.') parser.add_option('', '--plugins-dir', action='append', dest='pluginsDirs', default=[], help='Looks in in the given directory for plugins and ' 'loads the tests from all of them.') parser.add_option('', '--exclude', action='append', dest='excludePlugins', default=[], help='List of plugins you do not want --plugins-dir ' 'to include.') parser.add_option('', '--disable-multiprocessing', action='store_true', dest='disableMultiprocessing', help='Disables multiprocessing stuff.') (options, args) = parser.parse_args() world.disableMultiprocessing = options.disableMultiprocessing # This must go before checking for args, of course. for pluginDir in options.pluginsDirs: for name in glob.glob(os.path.join(pluginDir, '*')): #print '***', name if not any(map(lambda x:name in x, map(glob.glob, options.excludePlugins))) and \ os.path.isdir(name): args.append(name) if not args: parser.print_help() sys.exit(-1) if options.timeout: test.timeout = options.timeout if options.trace: traceFilename = conf.supybot.directories.log.dirize('trace.log') fd = open(traceFilename, 'w') sys.settrace(utils.gen.callTracer(fd)) atexit.register(fd.close) atexit.register(lambda : sys.settrace(None)) if options.verbose: world.myVerbose = True else: world.myVerbose = False if options.nonetwork: test.network = False log.testing = True world.testing = True args = [s.rstrip('\\/') for s in args] pluginDirs = set([os.path.dirname(s) or '.' for s in args]) conf.supybot.directories.plugins.setValue(list(pluginDirs)) pluginNames = set([os.path.basename(s) for s in args]) load = unittest.defaultTestLoader.loadTestsFromModule for pluginName in pluginNames: if pluginName.endswith('.py'): pluginName = pluginName[:-3] try: pluginModule = plugin.loadPluginModule(pluginName) except (ImportError, callbacks.Error) as e: sys.stderr.write('Failed to load plugin %s:' % pluginName) traceback.print_exc() sys.stderr.write('(pluginDirs: %s)\n' % conf.supybot.directories.plugins()) continue if hasattr(pluginModule, 'test'): test.suites.append(load(pluginModule.test)) suite = unittest.TestSuite(test.suites) runner = unittest.TextTestRunner(verbosity=2) print('Testing began at %s (pid %s)' % (time.ctime(), os.getpid())) if options.clean: shutil.rmtree(conf.supybot.directories.log()) shutil.rmtree(conf.supybot.directories.conf()) shutil.rmtree(conf.supybot.directories.data()) result = runner.run(suite) if hasattr(unittest, 'asserts'): print('Total asserts: %s' % unittest.asserts) if result.wasSuccessful(): sys.exit(0) else: sys.exit(1) # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: