diff options
author | Fabrice Douchant <Fabrice.Douchant@logilab.fr> | 2008-10-24 11:30:39 +0200 |
---|---|---|
committer | Fabrice Douchant <Fabrice.Douchant@logilab.fr> | 2008-10-24 11:30:39 +0200 |
commit | e21872eded44b7e631cd4d197747d48d25e4e86a (patch) | |
tree | ff5952895f8fb75397150ed17cd72a782b051974 | |
parent | 718e57155211188be3e6c9c61bc34bbc5670e4d8 (diff) | |
download | logilab-common-e21872eded44b7e631cd4d197747d48d25e4e86a.tar.gz |
[#5555] add new pytest option restart that passes tests which succeeded (see pytest -h)
-rw-r--r-- | pytest.py | 30 | ||||
-rw-r--r-- | testlib.py | 66 |
2 files changed, 90 insertions, 6 deletions
@@ -325,6 +325,7 @@ class PyTester(object): self.report = GlobalTestReport() self.cvg = cvg self.options = options + self.firstwrite = True def show_report(self): """prints the report and returns appropriate exitcode""" @@ -360,10 +361,20 @@ class PyTester(object): """finds each testfile in the `testdir` and runs it""" for filename in abspath_listdir(testdir): if this_is_a_testfile(filename): + if self.options.exitfirst and not self.options.restart: + # overwrite restart file + try: + restartfile = open(testlib.FILE_RESTART, "w") + restartfile.close() + except Exception, e: + print >> sys.__stderr__, "Error while overwriting \ +succeeded test file :", osp.join(os.getcwd(),testlib.FILE_RESTART) + raise e # run test and collect information prog = self.testfile(filename, batchmode=True) if exitfirst and (prog is None or not prog.result.wasSuccessful()): break + self.firstwrite = True # clean local modules remove_local_modules_from_sys(testdir) @@ -377,6 +388,15 @@ class PyTester(object): dirname = osp.dirname(filename) if dirname: os.chdir(dirname) + # overwrite restart file if it has not been done already + if self.options.exitfirst and not self.options.restart and self.firstwrite: + try: + restartfile = open(testlib.FILE_RESTART, "w") + restartfile.close() + except Exception, e: + print >> sys.__stderr__, "Error while overwriting \ +succeeded test file :", osp.join(os.getcwd(),testlib.FILE_RESTART) + raise e modname = osp.basename(filename)[:-3] if batchmode: from cStringIO import StringIO @@ -560,9 +580,14 @@ def make_parser(): dest="pdb", action="callback", help="Enable test failure inspection (conflicts with --coverage)") parser.add_option('-x', '--exitfirst', callback=rebuild_and_store, - dest="exitfirst", + dest="exitfirst", default=False, action="callback", help="Exit on first failure " "(only make sense when pytest run one test file)") + parser.add_option('-r', '--restart', callback=rebuild_and_store, + dest="restart", default=False, + action="callback", + help="Restart tests from where it failed (implies exitfirst) " + "(only make sense if tests previously ran with exitfirst only)") parser.add_option('-c', '--capture', callback=rebuild_cmdline, action="callback", help="Captures and prints standard out/err only on errors " @@ -626,6 +651,9 @@ def parseargs(parser): newargs.extend(['--printonly', options.printonly]) if options.skipped: newargs.extend(['--skip', options.skipped]) + # restart implies exitfirst + if options.restart: + options.exitfirst = True # append additional args to the new sys.argv and let unittest_main # do the rest newargs += args @@ -80,6 +80,8 @@ DEFAULT_PREFIXES = ('test', 'regrtest', 'smoketest', 'unittest', ENABLE_DBC = False +FILE_RESTART = ".restart" + def with_tempdir(callable): """A decorator ensuring no temporary file left when the function return @@ -118,7 +120,7 @@ def main(testdir=None, exitafter=True): """ try: - opts, args = getopt.getopt(sys.argv[1:], 'hvqx:t:pcd', ['help']) + opts, args = getopt.getopt(sys.argv[1:], 'hvqxr:t:pcd', ['help']) except getopt.error, msg: print msg print __doc__ @@ -431,11 +433,11 @@ class SkipAwareTestResult(unittest._TextTestResult): # `err_color` is a unicode string, encode it before writing # to stdout if hasattr(self.stream, 'encoding'): - err_color = err_color.encode(self.stream.encoding) + err_color = err_color.encode(self.stream.encoding, 'replace') else: # rare cases where test ouput has been hijacked, pick # up a random encoding - err_color = err_color.encode('utf-8') + err_color = err_color.encode('utf-8', 'replace') self.stream.writeln(err_color) else: self.stream.writeln(err) @@ -764,9 +766,9 @@ Examples: self.tags_pattern = None import getopt try: - options, args = getopt.getopt(argv[1:], 'hHvixqcp:s:m:', + options, args = getopt.getopt(argv[1:], 'hHvixrqcp:s:m:', ['help', 'verbose', 'quiet', 'pdb', - 'exitfirst', 'capture', 'printonly=', + 'exitfirst', 'restart', 'capture', 'printonly=', 'skip=', 'match=']) for opt, value in options: if opt in ('-h', '-H', '--help'): @@ -775,6 +777,9 @@ Examples: self.pdbmode = True if opt in ('-x', '--exitfirst'): self.exitfirst = True + if opt in ('-r', '--restart'): + self.restart = True + self.exitfirst = True if opt in ('-q', '--quiet'): self.verbosity = 0 if opt in ('-v', '--verbose'): @@ -827,6 +832,40 @@ Examples: test_pattern=self.test_pattern, skipped_patterns=self.skipped_patterns, options=self.options) + + def removeSucceededTests(obj, succTests): + """ Recurcive function that removes succTests from + a TestSuite or TestCase + """ + if isinstance(obj, TestSuite): + removeSucceededTests(obj._tests, succTests) + if isinstance(obj, list): + for el in obj[:]: + if isinstance(el, TestSuite): + removeSucceededTests(el, succTests) + elif isinstance(el, TestCase): + descr = '.'.join((el.__class__.__module__, + el.__class__.__name__, + el._testMethodName)) + if descr in succTests: + obj.remove(el) + + # retrieve succeeded tests from FILE_RESTART + try: + restartfile = open(FILE_RESTART, 'r') + try: + succeededtests = list(elem.rstrip('\n\r') for elem in + restartfile.readlines()) + removeSucceededTests(self.test, succeededtests) + except Exception, e: + raise e + finally: + restartfile.close() + except Exception ,e: + print >> sys.__stderr__, "Error while reading \ +succeeded tests into", osp.join(os.getcwd(),FILE_RESTART) + raise e + result = self.testRunner.run(self.test) if hasattr(self.module, 'teardown_module'): try: @@ -1140,6 +1179,23 @@ class TestCase(unittest.TestCase): if not self.quiet_run(result, self.tearDown): return if success: + if hasattr(options, "exitfirst") and options.exitfirst: + # add this test to restart file + try: + restartfile = open(FILE_RESTART, 'a') + try: + descr = '.'.join((self.__class__.__module__, + self.__class__.__name__, + self._testMethodName)) + restartfile.write(descr+os.linesep) + except Exception, e: + raise e + finally: + restartfile.close() + except Exception, e: + print >> sys.__stderr__, "Error while saving \ +succeeded test into", osp.join(os.getcwd(),FILE_RESTART) + raise e result.addSuccess(self) finally: # if result.cvg: |