Title: [129138] trunk/Tools
Revision
129138
Author
[email protected]
Date
2012-09-20 08:48:36 -0700 (Thu, 20 Sep 2012)

Log Message

[GTK] run-api-tests should not buffer test stdout
https://bugs.webkit.org/show_bug.cgi?id=88474

Reviewed by Philippe Normand.

* Scripts/run-gtk-tests:
(TestRunner._run_test_command): Use os.forkpty() instead of
subprocess.Popen() so that gtest sends the output with colors to
stdout. Use common.parse_output_lines() to parse the output and
write it to stdout while it's read.
(TestRunner._run_test_command.parse_line): Parse the line to get
the test pid and write the line to stdout.
(TestRunner._run_test_command.waitpid): Helper function to call
waitpid handling EINTR.
(TestRunner._run_test_command.return_code_from_exit_status):
Helper function to convert exit status of test commands to a
return code.
* gtk/common.py:
(parse_output_lines): Helper function that uses select to read
the given file descriptor and call the given callback for every
line read.

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (129137 => 129138)


--- trunk/Tools/ChangeLog	2012-09-20 15:25:06 UTC (rev 129137)
+++ trunk/Tools/ChangeLog	2012-09-20 15:48:36 UTC (rev 129138)
@@ -1,3 +1,27 @@
+2012-09-20  Carlos Garcia Campos  <[email protected]>
+
+        [GTK] run-api-tests should not buffer test stdout
+        https://bugs.webkit.org/show_bug.cgi?id=88474
+
+        Reviewed by Philippe Normand.
+
+        * Scripts/run-gtk-tests:
+        (TestRunner._run_test_command): Use os.forkpty() instead of
+        subprocess.Popen() so that gtest sends the output with colors to
+        stdout. Use common.parse_output_lines() to parse the output and
+        write it to stdout while it's read.
+        (TestRunner._run_test_command.parse_line): Parse the line to get
+        the test pid and write the line to stdout.
+        (TestRunner._run_test_command.waitpid): Helper function to call
+        waitpid handling EINTR.
+        (TestRunner._run_test_command.return_code_from_exit_status):
+        Helper function to convert exit status of test commands to a
+        return code.
+        * gtk/common.py:
+        (parse_output_lines): Helper function that uses select to read
+        the given file descriptor and call the given callback for every
+        line read.
+
 2012-09-20  Simon Hausmann  <[email protected]>
 
         [Qt] Fix initial build

Modified: trunk/Tools/Scripts/run-gtk-tests (129137 => 129138)


--- trunk/Tools/Scripts/run-gtk-tests	2012-09-20 15:25:06 UTC (rev 129137)
+++ trunk/Tools/Scripts/run-gtk-tests	2012-09-20 15:48:36 UTC (rev 129138)
@@ -213,27 +213,61 @@
         def alarm_handler(signum, frame):
             raise TestTimeout
 
-        p = subprocess.Popen(command, stdout=subprocess.PIPE, env=self._test_env)
+        child_pid = [-1]
+        def parse_line(line, child_pid = child_pid):
+            if child_pid[0] == -1:
+                child_pid[0] = self._get_child_pid_from_test_output(line)
+            sys.stdout.write(line)
+
+        def waitpid(pid):
+            while True:
+                try:
+                    return os.waitpid(pid, 0)
+                except (OSError, IOError) as e:
+                    if e.errno == errno.EINTR:
+                        continue
+                    raise
+
+        def return_code_from_exit_status(status):
+            if os.WIFSIGNALED(status):
+                return -os.WTERMSIG(status)
+            elif os.WIFEXITED(status):
+                return os.WEXITSTATUS(status)
+            else:
+                # Should never happen
+                raise RuntimeError("Unknown child exit status!")
+
+        pid, fd = os.forkpty()
+        if pid == 0:
+            os.execvpe(command[0], command, self._test_env)
+            sys.exit(0)
+
         if timeout > 0:
             signal(SIGALRM, alarm_handler)
             alarm(timeout)
 
-        stdout = ""
         try:
-            stdout = p.communicate()[0]
+            common.parse_output_lines(fd, parse_line)
             if timeout > 0:
                 alarm(0)
-            sys.stdout.write(stdout)
-            sys.stdout.flush()
         except TestTimeout:
-            self._kill_process(p.pid)
-            child_pid = self._get_child_pid_from_test_output(stdout)
-            if child_pid > 0:
-                self._kill_process(child_pid)
+            self._kill_process(pid)
+            if child_pid[0] > 0:
+                self._kill_process(child_pid[0])
             raise
 
-        return not p.returncode
+        try:
+            dummy, status = waitpid(pid)
+        except OSError as e:
+            if e.errno != errno.ECHILD:
+                raise
+            # This happens if SIGCLD is set to be ignored or waiting
+            # for child processes has otherwise been disabled for our
+            # process.  This child is dead, we can't get the status.
+            status = 0
 
+        return not return_code_from_exit_status(status)
+
     def _run_test_glib(self, test_program):
         tester_command = ['gtester']
         if self._options.verbose:

Modified: trunk/Tools/gtk/common.py (129137 => 129138)


--- trunk/Tools/gtk/common.py	2012-09-20 15:25:06 UTC (rev 129137)
+++ trunk/Tools/gtk/common.py	2012-09-20 15:48:36 UTC (rev 129138)
@@ -15,7 +15,9 @@
 # License along with this library; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
+import errno
 import os
+import select
 import subprocess
 import sys
 
@@ -102,3 +104,32 @@
     if 'gtk+-3.0' in stdout:
         return 3
     return 2
+
+
+def parse_output_lines(fd, parse_line_callback):
+    output = ''
+    read_set = [fd]
+    while read_set:
+        rlist, wlist, xlist = select.select(read_set, [], [])
+
+        if fd in rlist:
+            try:
+                chunk = os.read(fd, 1024)
+            except OSError as e:
+                if e.errno == errno.EIO:
+                    # Child process finished.
+                    chunk = ''
+                else:
+                    raise e
+            if not chunk:
+                read_set.remove(fd)
+
+            output += chunk
+            while '\n' in output:
+                pos = output.find('\n')
+                parse_line_callback(output[:pos + 1])
+                output = output[pos + 1:]
+
+            if len(chunk) < 1024 and output:
+                parse_line_callback(output)
+                output = ''
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to