def __init__(self, reporter, janitor, benchmark=0): self.reporter = IReporter(reporter) self.janitor = itrial.IJanitor(janitor) # XXX NO NO NO NO NO NO NO NO NO NO GOD DAMNIT NO YOU CANNOT DO THIS # IT IS NOT ALLOWED DO NOT CALL WAIT() ANYWHERE EVER FOR ANY REASON # *EVER* util.wait(self.reporter.setUpReporter()) self.benchmark = benchmark self.startTime, self.endTime = None, None self.numTests = 0 self.couldNotImport = {} self.tests = [] self.children = [] if benchmark: self._registerBenchmarkAdapters()
class TestSuite(Timed): """This is the main organizing object. The front-end script creates a TestSuite, and tells it what modules were requested on the command line. It also hands it a reporter. The TestSuite then takes all of the packages, modules, classes and methods, and adapts them to ITestRunner objects, which it then calls the runTests method on. """ zi.implements(itrial.ITestSuite) moduleGlob = 'test_*.py' sortTests = 1 debugger = False dryRun = False def __init__(self, reporter, janitor, benchmark=0): self.reporter = IReporter(reporter) self.janitor = itrial.IJanitor(janitor) # XXX NO NO NO NO NO NO NO NO NO NO GOD DAMNIT NO YOU CANNOT DO THIS # IT IS NOT ALLOWED DO NOT CALL WAIT() ANYWHERE EVER FOR ANY REASON # *EVER* util.wait(self.reporter.setUpReporter()) self.benchmark = benchmark self.startTime, self.endTime = None, None self.numTests = 0 self.couldNotImport = {} self.tests = [] self.children = [] if benchmark: self._registerBenchmarkAdapters() def _registerBenchmarkAdapters(self): from twisted import trial trial.benchmarking = True def addMethod(self, method): self.tests.append(method) def _getMethods(self): for runner in self.children: for meth in runner.children: yield meth methods = property(_getMethods) def addTestClass(self, testClass): if ITestCaseFactory.providedBy(testClass): self.tests.append(testClass) else: warnings.warn(("didn't add %s because it does not implement " "ITestCaseFactory" % testClass)) def addModule(self, module): if isinstance(module, types.StringType): _dbgPA("addModule: %r" % (module,)) try: module = reflect.namedModule(module) except: self.couldNotImport[module] = failure.Failure() return if isinstance(module, types.ModuleType): _dbgPA("adding module: %r" % module) self.tests.append(module) if hasattr(module, '__doctests__'): vers = sys.version_info[0:2] if vers[0] >= 2 and vers[1] >= 3: runner = itrial.ITestRunner(getattr(module, '__doctests__')) self.tests.append(runner) else: warnings.warn(("trial's doctest support only works with " "python 2.3 or later, not running doctests")) def addDoctest(self, obj): # XXX: this is a crap adaptation, ListType is adapted to # ITestRunner by tdoctest.ModuleDocTestsRunner # it is crappy crap, awful dreadful crap self.tests.append(itrial.ITestRunner([obj])) def addPackage(self, package): modGlob = os.path.join(os.path.dirname(package.__file__), self.moduleGlob) modules = map(reflect.filenameToModuleName, glob.glob(modGlob)) for module in modules: self.addModule(module) def _packageRecurse(self, arg, dirname, names): # Only recurse into packages for ext in 'py', 'so', 'pyd', 'dll': if os.path.exists(os.path.join(dirname, os.extsep.join(('__init__', ext)))): break else: return testModuleNames = fnmatch.filter(names, self.moduleGlob) testModules = [ reflect.filenameToModuleName(opj(dirname, name)) for name in testModuleNames ] for module in testModules: self.addModule(module) def addPackageRecursive(self, package): packageDir = os.path.dirname(package.__file__) os.path.walk(packageDir, self._packageRecurse, None) def _getBenchmarkStats(self): stat = {} for r in self.children: for m in r.children: stat.update(getattr(m, 'benchmarkStats', {})) return stat benchmarkStats = property(_getBenchmarkStats) #### # the root of the ParentAttributeMixin tree def getJanitor(self): return self.janitor def getReporter(self): return self.reporter def isDebuggingRun(self): return self.debugger def isDryRun(self): return self.dryRun #### def _bail(self): from twisted.internet import reactor d = defer.Deferred() reactor.addSystemEventTrigger('after', 'shutdown', lambda: d.callback(None)) reactor.fireSystemEvent('shutdown') # radix's suggestion treactor = interfaces.IReactorThreads(reactor, None) if treactor is not None: treactor.suggestThreadPoolSize(0) util.wait(d) # so that the shutdown event completes def _initLogging(self): log.startKeepingErrors() def run(self, seed=None): self.startTime = time.time() tests = self.tests if self.sortTests: # XXX twisted.python.util.dsu(tests, str) tests.sort(lambda x, y: cmp(str(x), str(y))) self._initLogging() # Kick-start things from twisted.internet import reactor reactor.callLater(0, reactor.crash) reactor.run() # randomize tests if requested r = None if seed is not None: r = random.Random(seed) r.shuffle(tests) self.reporter.write('Running tests shuffled with seed %d' % seed) try: # this is where the test run starts # eventually, the suite should call reporter.startSuite() with # the predicted number of tests to be run try: for test in tests: tr = itrial.ITestRunner(test) self.children.append(tr) tr.parent = self try: tr.runTests(randomize=(seed is not None)) except KeyboardInterrupt: # KeyboardInterrupts are normal, not a bug in trial. # Just stop the test run, and do the usual reporting. raise except: # Any other exception is problem. Report it. f = failure.Failure() annoyingBorder = "-!*@&" * 20 trialIsBroken = """ \tWHOOP! WHOOP! DANGER WILL ROBINSON! DANGER! WHOOP! WHOOP! \tcaught exception in TestSuite! \n\n\t\tTRIAL IS BROKEN!\n\n \t%s""" % ('\n\t'.join(f.getTraceback().split('\n')),) print "\n%s\n%s\n\n%s\n" % \ (annoyingBorder, trialIsBroken, annoyingBorder) except KeyboardInterrupt: log.msg(iface=ITrialDebug, kbd="KEYBOARD INTERRUPT") for name, exc in self.couldNotImport.iteritems(): # XXX: AFAICT this is only used by RemoteJellyReporter self.reporter.reportImportError(name, exc) if self.benchmark: pickle.dump(self.benchmarkStats, file("test.stats", 'wb')) finally: self.endTime = time.time() # hand the reporter the TestSuite to give it access to all information # from the test run self.reporter.endSuite(self) try: util.wait(self.reporter.tearDownReporter()) except: t, v, tb = sys.exc_info() raise RuntimeError, "your reporter is broken %r" % \ (''.join(v),), tb self._bail()