tests/run-tests.py
changeset 2571 83cfd95eafb5
parent 2570 2264b2b077a1
child 2576 6a961a54f953
--- a/tests/run-tests.py	Thu Jul 06 10:09:24 2006 -0700
+++ b/tests/run-tests.py	Thu Jul 06 11:45:34 2006 -0700
@@ -7,23 +7,32 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-import os, sys, shutil, re
+import difflib
+import errno
+import optparse
+import os
+import popen2
+import re
+import shutil
+import signal
+import sys
 import tempfile
-import difflib
-import popen2
-from optparse import OptionParser
+import time
 
 required_tools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed"]
 
-parser = OptionParser("%prog [options] [tests]")
+parser = optparse.OptionParser("%prog [options] [tests]")
 parser.add_option("-v", "--verbose", action="store_true",
     help="output verbose messages")
+parser.add_option("-t", "--timeout", type="int",
+    help="output verbose messages")
 parser.add_option("-c", "--cover", action="store_true",
     help="print a test coverage report")
 parser.add_option("-s", "--cover_stdlib", action="store_true",
     help="print a test coverage report inc. standard libraries")
 parser.add_option("-C", "--annotate", action="store_true",
     help="output files annotated with coverage")
+parser.set_defaults(timeout=30)
 (options, args) = parser.parse_args()
 verbose = options.verbose
 coverage = options.cover or options.cover_stdlib or options.annotate
@@ -159,6 +168,12 @@
         vlog("# Running: "+cmd)
         os.system(cmd)
 
+class Timeout(Exception):
+    pass
+
+def alarmed(signum, frame):
+    raise Timeout
+
 def run(cmd):
     """Run command in a sub-process, capturing the output (stdout and stderr).
     Return the exist code, and output."""
@@ -172,9 +187,17 @@
             ret = 0
     else:
         proc = popen2.Popen4(cmd)
-        proc.tochild.close()
-        output = proc.fromchild.read()
-        ret = proc.wait()
+        try:
+            output = ''
+            proc.tochild.close()
+            output = proc.fromchild.read()
+            ret = proc.wait()
+        except Timeout:
+            vlog('# Process %d timed out - killing it' % proc.pid)
+            os.kill(proc.pid, signal.SIGTERM)
+            ret = proc.wait()
+            if ret == 0:
+                ret = signal.SIGTERM << 8
     return ret, splitnewlines(output)
 
 def run_one(test):
@@ -204,10 +227,16 @@
     if os.name == 'nt' and test.endswith(".bat"):
         cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test))
 
+    if options.timeout > 0:
+        signal.alarm(options.timeout)
+
     vlog("# Running", cmd)
     ret, out = run(cmd)
     vlog("# Ret was:", ret)
 
+    if options.timeout > 0:
+        signal.alarm(0)
+
     diffret = 0
     # If reference output file exists, check test output against it
     if os.path.exists(ref):
@@ -231,6 +260,30 @@
             f.write(line)
         f.close()
 
+    # Kill off any leftover daemon processes
+    try:
+        fp = file(DAEMON_PIDS)
+        for line in fp:
+            try:
+                pid = int(line)
+            except ValueError:
+                continue
+            try:
+                os.kill(pid, 0)
+                vlog('# Killing daemon process %d' % pid)
+                os.kill(pid, signal.SIGTERM)
+                time.sleep(0.25)
+                os.kill(pid, 0)
+                vlog('# Daemon process %d is stuck - really killing it' % pid)
+                os.kill(pid, signal.SIGKILL)
+            except OSError, err:
+                if err.errno != errno.ESRCH:
+                    raise
+        fp.close()
+        os.unlink(DAEMON_PIDS)
+    except IOError:
+        pass
+
     os.chdir(TESTDIR)
     shutil.rmtree(tmpd, True)
     return ret == 0
@@ -252,6 +305,8 @@
 
 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
 HGTMP   = os.environ["HGTMP"]   = tempfile.mkdtemp("", "hgtests.")
+DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
+
 vlog("# Using TESTDIR", TESTDIR)
 vlog("# Using HGTMP", HGTMP)
 
@@ -264,6 +319,15 @@
     try:
         install_hg()
 
+        if options.timeout > 0:
+            try:
+                signal.signal(signal.SIGALRM, alarmed)
+                vlog('# Running tests with %d-second timeout' %
+                     options.timeout)
+            except AttributeError:
+                print 'WARNING: cannot run tests with timeouts'
+                options.timeout = 0
+
         tests = 0
         failed = 0