From 740c5aabc85dd3a40d739f485311154ca241a71e Mon Sep 17 00:00:00 2001
From: Guido Trotter <ultrotter@google.com>
Date: Mon, 23 Jun 2008 12:50:15 +0000
Subject: [PATCH] Fix the zombie process unittest

The failure is because in high load, the parent gets to run before the
child has the chance to os._exit(), and therefore it is still running
when the parent does the check.

The fix removes the chance of this happening by waiting to receive a SIGCHLD
(but not calling wait()) before trying to test the pid.

Reviewed-by: imsnah
---
 test/ganeti.utils_unittest.py | 36 ++++++++++++++++++++++++++++-------
 1 file changed, 29 insertions(+), 7 deletions(-)

diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py
index abc4a7692..c5f8cfda6 100755
--- a/test/ganeti.utils_unittest.py
+++ b/test/ganeti.utils_unittest.py
@@ -28,6 +28,7 @@ import tempfile
 import os.path
 import os
 import md5
+import signal
 import socket
 import shutil
 import re
@@ -43,16 +44,16 @@ from ganeti.utils import IsProcessAlive, Lock, Unlock, RunCmd, \
      SetEtcHostsEntry, RemoveEtcHostsEntry
 from ganeti.errors import LockError, UnitParseError
 
+def _ChildHandler(signal, stack):
+  global _ChildFlag
+  _ChildFlag = True
 
 class TestIsProcessAlive(unittest.TestCase):
   """Testing case for IsProcessAlive"""
+
   def setUp(self):
-    # create a zombie and a (hopefully) non-existing process id
-    self.pid_zombie = os.fork()
-    if self.pid_zombie == 0:
-      os._exit(0)
-    elif self.pid_zombie < 0:
-      raise SystemError("can't fork")
+    global _ChildFlag
+    # create a (most probably) non-existing process-id
     self.pid_non_existing = os.fork()
     if self.pid_non_existing == 0:
       os._exit(0)
@@ -60,7 +61,18 @@ class TestIsProcessAlive(unittest.TestCase):
       os.waitpid(self.pid_non_existing, 0)
     else:
       raise SystemError("can't fork")
+    _ChildFlag = False
+    # Use _ChildHandler for SIGCHLD
+    self.chldOrig = signal.signal(signal.SIGCHLD, _ChildHandler)
+    # create a zombie
+    self.pid_zombie = os.fork()
+    if self.pid_zombie == 0:
+      os._exit(0)
+    elif self.pid_zombie < 0:
+      raise SystemError("can't fork")
 
+  def tearDown(self):
+    signal.signal(signal.SIGCHLD, self.chldOrig)
 
   def testExists(self):
     mypid = os.getpid()
@@ -68,10 +80,20 @@ class TestIsProcessAlive(unittest.TestCase):
                  "can't find myself running")
 
   def testZombie(self):
+    global _ChildFlag
+    timeout = 10
+
+    while not _ChildFlag:
+      if timeout >= 0:
+        time.sleep(0.2)
+        timeout -= 0.2
+      else:
+        self.fail("timed out waiting for child's signal")
+        break # not executed...
+
     self.assert_(not IsProcessAlive(self.pid_zombie),
                  "zombie not detected as zombie")
 
-
   def testNotExisting(self):
     self.assert_(not IsProcessAlive(self.pid_non_existing),
                  "noexisting process detected")
-- 
GitLab