Rev 4173: Merge fixes into lifeless in file:///home/vila/src/bzr/experimental/parallel-selftest/

Vincent Ladeuil v.ladeuil+lp at free.fr
Fri Mar 20 15:26:27 GMT 2009


At file:///home/vila/src/bzr/experimental/parallel-selftest/

------------------------------------------------------------
revno: 4173
revision-id: v.ladeuil+lp at free.fr-20090320152625-su1l80tcpfmn62v0
parent: v.ladeuil+lp at free.fr-20090320080433-gc5wja5qb0k6rz7z
parent: v.ladeuil+lp at free.fr-20090320150019-4dbvqrhlbhzvx4m1
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: lifeless
timestamp: Fri 2009-03-20 16:26:25 +0100
message:
  Merge fixes into lifeless
modified:
  bzrlib/tests/blackbox/test_breakin.py test_breakin.py-20070424043903-qyy6zm4pj3h4sbp3-1
    ------------------------------------------------------------
    revno: 4167.3.4
    revision-id: v.ladeuil+lp at free.fr-20090320150019-4dbvqrhlbhzvx4m1
    parent: v.ladeuil+lp at free.fr-20090320080427-kghpz6mrh9l7ywpq
    committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
    branch nick: fixes
    timestamp: Fri 2009-03-20 16:00:19 +0100
    message:
      More robust handling of test_breakin.
      
      * bzrlib/tests/blackbox/test_breakin.py:
      (TestBreakin.test_breakin): If the process doesn't quit
      peacefully, kill it to avoid leaks.
    modified:
      bzrlib/tests/blackbox/test_breakin.py test_breakin.py-20070424043903-qyy6zm4pj3h4sbp3-1
-------------- next part --------------
=== modified file 'bzrlib/tests/blackbox/test_breakin.py'
--- a/bzrlib/tests/blackbox/test_breakin.py	2009-03-20 08:01:16 +0000
+++ b/bzrlib/tests/blackbox/test_breakin.py	2009-03-20 15:26:25 +0000
@@ -16,13 +16,17 @@
 
 """Blackbox tests for debugger breakin"""
 
+import errno
 import os
 import signal
 import subprocess
 import sys
 import time
 
-from bzrlib import tests
+from bzrlib import (
+    errors,
+    tests,
+    )
 
 
 class TestBreakin(tests.TestCase):
@@ -44,11 +48,38 @@
             raise tests.TestNotApplicable(
                 '%s raises a popup on OSX' % self.id())
 
+    def _wait_for_process(self, pid, sig=None):
+        # We don't know quite how long waiting for the process 'pid' will take,
+        # but if it's more than 10s then it's probably not going to work.
+        for i in range(100):
+            time.sleep(0.1)
+            if sig is not None:
+                os.kill(pid, sig)
+            # Use WNOHANG to ensure we don't get blocked, doing so, we may
+            # leave the process continue after *we* die...
+            try:
+                # note: waitpid is different on win32, but this test only runs
+                # on unix
+                pid_killed, returncode = os.waitpid(pid, os.WNOHANG)
+                if (pid_killed, returncode) != (0, 0):
+                    if sig is not None:
+                        # high bit in low byte says if core was dumped; we
+                        # don't care
+                        status, sig = (returncode >> 8, returncode & 0x7f)
+                        return True, sig
+            except OSError, e:
+                if e.errno in (errno.ECHILD, errno.ESRCH):
+                    # The process doesn't exist anymore
+                    return True, None
+                else:
+                    raise
+
+        return False, None
+
     # port 0 means to allocate any port
     _test_process_args = ['serve', '--port', 'localhost:0']
 
     def test_breakin(self):
-        """Once called, the debugger can be exited and finishes the process."""
         # Break in to a debugger while bzr is running
         # we need to test against a command that will wait for
         # a while -- bzr serve should do
@@ -63,7 +94,18 @@
         self.assertContainsRe(err, r'entering debugger')
         # Now that the debugger is entered, we can ask him to quit
         proc.stdin.write("q\n")
-        # And the subprocess should just die quietly...
+        # We wait a bit to let the child process handles our query and avoid
+        # triggering deadlocks leading to hangs on multi-core hosts...
+        dead, sig = self._wait_for_process(proc.pid)
+        if not dead:
+            # The process didn't finish, let's kill it before reporting failure
+            dead, sig = self._wait_for_process(proc.pid, signal.SIGKILL)
+            if dead:
+                raise tests.KnownFailure(
+                    "subprocess wasn't terminated, it had to be killed")
+            else:
+                self.fail("subprocess %d wasn't terminated by repeated SIGKILL",
+                          proc.pid)
 
     def test_breakin_harder(self):
         """SIGQUITting twice ends the process."""
@@ -79,18 +121,9 @@
         # validating the first get received and produce its effect).
         err = proc.stderr.readline()
         self.assertContainsRe(err, r'entering debugger')
-        # Now a second signal should make it quit. We don't know quite how long
-        # this will take, but if it's more than 10s then it's probably not
-        # going to work.
-        os.kill(proc.pid, signal.SIGQUIT)
-        # note: waitpid is different on win32, but this test only runs on
-        # unix
-        r = os.waitpid(proc.pid, 0)
-        if r != (0, 0):
-            # high bit says if core was dumped; we don't care
-            self.assertEquals(signal.SIGQUIT, r[1] & 0x7f)
-        else:
-            self.fail("subprocess wasn't terminated by repeated SIGQUIT")
+        dead, sig = self._wait_for_process(proc.pid, signal.SIGQUIT)
+        self.assertTrue((dead and sig == signal.SIGQUIT),
+                        msg="subprocess wasn't terminated by repeated SIGQUIT")
 
     def test_breakin_disabled(self):
         self._dont_SIGQUIT_on_darwin()



More information about the bazaar-commits mailing list