Bug 793855 - runxpcshelltests.py should check the test process has exited and if not, output a TBPL-compatible error; r=gps,jmaher
authorEd Morley <emorley@mozilla.com>
Sun, 07 Oct 2012 21:21:30 +0100
changeset 109575 9a685a97bfec
parent 109574 0c48cbf5e4c5
child 109576 db8552af8d73
push id16084
push useremorley@mozilla.com
push dateSun, 07 Oct 2012 20:26:16 +0000
treeherdermozilla-inbound@db8552af8d73 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps, jmaher
bugs793855
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 793855 - runxpcshelltests.py should check the test process has exited and if not, output a TBPL-compatible error; r=gps,jmaher
testing/xpcshell/remotexpcshelltests.py
testing/xpcshell/runxpcshelltests.py
--- a/testing/xpcshell/remotexpcshelltests.py
+++ b/testing/xpcshell/remotexpcshelltests.py
@@ -219,27 +219,36 @@ class XPCShellRemote(xpcshell.XPCShellTe
         outputFile = "xpcshelloutput"
         f = open(outputFile, "w+")
         self.shellReturnCode = self.device.shell(cmd, f, cwd=self.remoteHere, env=env)
         f.close()
         # The device manager may have timed out waiting for xpcshell.
         # Guard against an accumulation of hung processes by killing
         # them here. Note also that IPC tests may spawn new instances
         # of xpcshell.
-        self.device.killProcess(cmd[0]);
-        self.device.killProcess("xpcshell");
+        self.device.killProcess(cmd[0])
+        self.device.killProcess("xpcshell")
         return outputFile
 
     def communicate(self, proc):
         f = open(proc, "r")
         contents = f.read()
         f.close()
         os.remove(proc)
         return contents, ""
 
+    def poll(self, proc):
+        if self.device.processExist("xpcshell") is None:
+          return self.getReturnCode(proc)
+        # Process is still running
+        return None
+
+    def kill(self, proc):
+        return self.device.killProcess("xpcshell", True)
+
     def getReturnCode(self, proc):
         if self.shellReturnCode is not None:
           return self.shellReturnCode
         else:
           return -1
 
     def removeDir(self, dirname):
         self.device.removeDir(dirname)
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -312,16 +312,30 @@ class XPCShellTests(object):
 
   def communicate(self, proc):
     """
       Simple wrapper to communicate with a process.
       On a remote system, this is overloaded to handle remote process communication.
     """
     return proc.communicate()
 
+  def poll(self, proc):
+    """
+      Simple wrapper to check if a process has terminated.
+      On a remote system, this is overloaded to handle remote process communication.
+    """
+    return proc.poll()
+
+  def kill(self, proc):
+    """
+      Simple wrapper to kill a process.
+      On a remote system, this is overloaded to handle remote process communication.
+    """
+    return proc.kill()
+
   def removeDir(self, dirname):
     """
       Simple wrapper to remove (recursively) a given directory.
       On a remote system, we need to overload this to work on the remote filesystem.
     """
     shutil.rmtree(dirname)
 
   def verifyDirPath(self, dirname):
@@ -855,16 +869,30 @@ class XPCShellTests(object):
           if os.path.isfile(childLog):
             leakLogs += [childLog]
         for log in leakLogs:
           dumpLeakLog(log, True)
 
         if self.logfiles and stdout:
           self.createLogFile(name, stdout, leakLogs)
       finally:
+        # We can sometimes get here before the process has terminated, which would
+        # cause removeDir() to fail - so check for the process & kill it it needed.
+        if self.poll(proc) is None:
+          message = "TEST-UNEXPECTED-FAIL | %s | Process still running after test!" % name
+          self.log.error(message)
+          print_stdout(stdout)
+          self.failCount += 1
+          xunitResult["passed"] = False
+          xunitResult["failure"] = {
+            "type": "TEST-UNEXPECTED-FAIL",
+            "message": message,
+            "text": stdout
+          }
+          self.kill(proc)
         # We don't want to delete the profile when running check-interactive
         # or check-one.
         if self.profileDir and not self.interactive and not self.singleFile:
           self.removeDir(self.profileDir)
       if gotSIGINT:
         xunitResult["passed"] = False
         xunitResult["time"] = "0.0"
         xunitResult["failure"] = {