run-tests: capture execution results in a TestResult class
authorGregory Szorc <gregory.szorc@gmail.com>
Sat, 19 Apr 2014 13:50:25 -0700
changeset 21305 d7a7825ff2cf
parent 21304 e626a67da4ba
child 21306 cbf5475827da
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().
tests/run-tests.py
--- 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)