summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabrice Douchant <Fabrice.Douchant@logilab.fr>2008-10-24 11:30:39 +0200
committerFabrice Douchant <Fabrice.Douchant@logilab.fr>2008-10-24 11:30:39 +0200
commite21872eded44b7e631cd4d197747d48d25e4e86a (patch)
treeff5952895f8fb75397150ed17cd72a782b051974
parent718e57155211188be3e6c9c61bc34bbc5670e4d8 (diff)
downloadlogilab-common-e21872eded44b7e631cd4d197747d48d25e4e86a.tar.gz
[#5555] add new pytest option restart that passes tests which succeeded (see pytest -h)
-rw-r--r--pytest.py30
-rw-r--r--testlib.py66
2 files changed, 90 insertions, 6 deletions
diff --git a/pytest.py b/pytest.py
index 844bd4f..16f39a4 100644
--- a/pytest.py
+++ b/pytest.py
@@ -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
diff --git a/testlib.py b/testlib.py
index 2af5f5e..674cf45 100644
--- a/testlib.py
+++ b/testlib.py
@@ -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: