run-tests: capture execution results in a TestResult class
Some implementation details of test execution still live outside of
Test. These include determining what a result means and cleaning up
after the test.
To move to the world where more of this logic can live inside Test or a
derived object, the logic for test execution needs to be refactored.
Specifically, exception trapping and opportunities for result processing
need to be moved into Test.
This patch starts the process by establishing a TestResult class for
holding the results of a test execution. In order to actually use this
class, exception trapping and execution time recording needed to be
moved into Test.run().
--- a/tests/run-tests.py Sat Apr 19 13:29:26 2014 -0700
+++ b/tests/run-tests.py Sat Apr 19 13:50:25 2014 -0700
@@ -563,10 +563,27 @@
env = self._getenv()
createhgrc(env['HGRCPATH'], self._options)
+ result = TestResult()
+ starttime = time.time()
+
+ def updateduration():
+ result.duration = time.time() - starttime
+
try:
- return self._run(self._replacements, env)
- finally:
- killdaemons(env['DAEMON_PIDS'])
+ ret, out = self._run(self._replacements, env)
+ updateduration()
+ result.ret = ret
+ result.out = out
+ except KeyboardInterrupt:
+ updateduration()
+ result.interrupted = True
+ except Exception, e:
+ updateduration()
+ result.exception = e
+
+ killdaemons(env['DAEMON_PIDS'])
+
+ return result
def _run(self, replacements, env):
raise NotImplemented('Subclasses must implement Test.run()')
@@ -625,6 +642,16 @@
return env
+class TestResult(object):
+ """Holds the result of a test execution."""
+
+ def __init__(self):
+ self.ret = None
+ self.out = None
+ self.duration = None
+ self.interrupted = False
+ self.exception = None
+
def pytest(test, wd, options, replacements, env):
py3kswitch = options.py3k_warnings and ' -3' or ''
cmd = '%s%s "%s"' % (PYTHON, py3kswitch, test)
@@ -1025,16 +1052,19 @@
os.remove(err) # Remove any previous output files
t = runner(testpath, options, count)
+ res = t.run()
- starttime = time.time()
- try:
- ret, out = t.run()
- except KeyboardInterrupt:
- endtime = time.time()
- log('INTERRUPTED: %s (after %d seconds)' % (test, endtime - starttime))
- raise
- endtime = time.time()
- times.append((test, endtime - starttime))
+ if res.interrupted:
+ log('INTERRUPTED: %s (after %d seconds)' % (test, res.duration))
+ raise KeyboardInterrupt()
+
+ if res.exception:
+ return fail('Exception during execution: %s' % res.exception, 255)
+
+ ret = res.ret
+ out = res.out
+
+ times.append((test, res.duration))
vlog("# Ret was:", ret)
skipped = (ret == SKIPPED_STATUS)