Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1454)

Unified Diff: Tools/Scripts/webkitpy/layout_tests/port/browser_test_driver.py

Issue 378113003: Modifications to layout test framework so that it can work with browser_tests. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Refactored browser_test.py by removing all the platform specific ports and created a class that cre… Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Tools/Scripts/webkitpy/layout_tests/port/browser_test_driver.py
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/browser_test_driver.py b/Tools/Scripts/webkitpy/layout_tests/port/browser_test_driver.py
new file mode 100644
index 0000000000000000000000000000000000000000..70e400f093aca37bd2e284f442dc7fc31b2fc437
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/browser_test_driver.py
@@ -0,0 +1,203 @@
+# Copyright (C) 2014 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the Google name nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitpy.layout_tests.port import driver
+import time
+
+
+class BrowserTestDriver(driver.Driver):
+ """Object for running print preview test(s) using browser_tests."""
+ def __init__(self, port, worker_number, pixel_tests, no_timeout=False):
+ """Invokes the constructor of driver.Driver."""
+ super(BrowserTestDriver, self).__init__(port, worker_number, pixel_tests, no_timeout)
+
+ def start(self, pixel_tests, per_test_args, deadline):
+ """Same as Driver.start() however, it has an extra step. It waits for
+ a path to a file to be used for stdin to be printed by the browser test.
+ If a path is found by the deadline test test will open the file and
+ assign it to the stdin of the process that is owned by this driver's
+ server process.
+ """
+ # FIXME(ivandavid): Need to handle case where the layout test doesn't
+ # get a file name.
+ new_cmd_line = self.cmd_line(pixel_tests, per_test_args)
+ if not self._server_process or new_cmd_line != self._current_cmd_line:
+ self._start(pixel_tests, per_test_args)
+ self._run_post_start_tasks()
+ path, found = self._read_stdin_path(time.time() + int(deadline) / 1000.0)
+ if found:
+ self._server_process._proc.stdin = open(path, 'w', 0)
Dirk Pranke 2014/07/10 23:37:13 I am worried that this approach won't actually wor
ivandavid 2014/07/16 21:29:01 I changed it to 'wb' so it can work on windows. Wh
+
+ def cmd_line(self, pixel_tests, per_test_args):
+ """Command line arguments to run the browser test."""
+ cmd = self._command_wrapper(self._port.get_option('wrapper'))
+ cmd.append(self._port._path_to_driver())
+ cmd.append('--gtest_filter=PrintPreviewPdfGeneratedBrowserTest.MANUAL_DummyTest')
+ cmd.append('--run-manual')
+ cmd.append('--single_process')
+ cmd.extend(per_test_args)
+ return cmd
+
+ def run_test(self, driver_input, stop_when_done):
+ """Run a single test and return the results.
+
+ Note that it is okay if a test times out or crashes and leaves
+ the driver in an indeterminate state. The upper layers of the program
+ are responsible for cleaning up and ensuring things are okay.
+
+ Returns a DriverOutput object.
+
+ This function was overriden because the new start function had to be
+ called.
Dirk Pranke 2014/07/10 23:37:13 I would modify Driver.start() to take an (optional
ivandavid 2014/07/16 21:29:01 Done.
+ """
+ start_time = time.time()
+ self.start(driver_input.should_run_pixel_test, driver_input.args, int(driver_input.timeout))
+ test_begin_time = time.time()
+ self.error_from_test = str()
+ self.err_seen_eof = False
+
+ command = self._command_from_driver_input(driver_input)
+ deadline = test_begin_time + int(driver_input.timeout) / 1000.0
+
+ self._server_process.write(command)
+ text, audio = self._read_first_block(deadline) # First block is either text or audio
+ image, actual_image_hash = self._read_optional_image_block(deadline) # The second (optional) block is image data.
+
+ crashed = self.has_crashed()
+ timed_out = self._server_process.timed_out
+ pid = self._server_process.pid()
+ leaked = self._leaked
+
+ if stop_when_done or crashed or timed_out or leaked:
+ # We call stop() even if we crashed or timed out in order to get any remaining stdout/stderr output.
+ # In the timeout case, we kill the hung process as well.
+ out, err = self._server_process.stop(self._port.driver_stop_timeout() if stop_when_done else 0.0)
+ if out:
+ text += out
+ if err:
+ self.error_from_test += err
+ self._server_process = None
+
+ crash_log = None
+ if crashed:
+ self.error_from_test, crash_log = self._get_crash_log(text, self.error_from_test, newer_than=start_time)
+
+ # If we don't find a crash log use a placeholder error message instead.
+ if not crash_log:
+ pid_str = str(self._crashed_pid) if self._crashed_pid else "unknown pid"
+ crash_log = 'No crash log found for %s:%s.\n' % (self._crashed_process_name, pid_str)
+ # If we were unresponsive append a message informing there may not have been a crash.
+ if self._subprocess_was_unresponsive:
+ crash_log += 'Process failed to become responsive before timing out.\n'
+
+ # Print stdout and stderr to the placeholder crash log; we want as much context as possible.
+ if self.error_from_test:
+ crash_log += '\nstdout:\n%s\nstderr:\n%s\n' % (text, self.error_from_test)
+ return driver.DriverOutput(text, image, actual_image_hash, audio,
+ crash=crashed, test_time=time.time() - test_begin_time, measurements=self._measurements,
+ timeout=timed_out, error=self.error_from_test,
+ crashed_process_name=self._crashed_process_name,
+ crashed_pid=self._crashed_pid, crash_log=crash_log,
+ leak=leaked, leak_log=self._leak_log,
+ pid=pid)
+
+ def _read_stdin_path(self, deadline):
+ """Reads the file path to be used for stdin."""
+ block = self._read_block(deadline)
+ if block.stdin_path:
+ return (block.stdin_path, True)
+ return (None, False)
+
+ def _process_stdout_line(self, block, line):
+ """Additional header read to look for the stdin path."""
+ if (self._read_header(block, line, 'StdinPath: ', 'stdin_path')):
+ return
+ super(BrowserTestDriver, self)._process_stdout_line(block, line)
+
+ def _read_block(self, deadline, wait_for_stderr_eof=False):
+ """Same as Driver._read_block() however rather than using ContentBlock,
+ ContentBlockStdin is used, as ContentBlock does not have the member
+ variable to store the stdin path.
+ """
+ block = ContentBlockStdin()
Dirk Pranke 2014/07/10 23:37:13 If this is the only difference from Driver._read_b
ivandavid 2014/07/16 21:29:01 Done.
+ out_seen_eof = False
+
+ while not self.has_crashed():
+ if out_seen_eof and (self.err_seen_eof or not wait_for_stderr_eof):
+ break
+
+ if self.err_seen_eof:
+ out_line = self._server_process.read_stdout_line(deadline)
+ err_line = None
+ elif out_seen_eof:
+ out_line = None
+ err_line = self._server_process.read_stderr_line(deadline)
+ else:
+ out_line, err_line = self._server_process.read_either_stdout_or_stderr_line(deadline)
+ if self._server_process.timed_out or self.has_crashed():
+ break
+
+ if out_line:
+ assert not out_seen_eof
+ out_line, out_seen_eof = self._strip_eof(out_line)
+ if err_line:
+ assert not self.err_seen_eof
+ err_line, self.err_seen_eof = self._strip_eof(err_line)
+
+ if out_line:
+ if out_line[-1] != "\n":
+ driver._log.error("Last character read from DRT stdout line was not a newline! This indicates either a NRWT or DRT bug.")
+ content_length_before_header_check = block._content_length
+ self._process_stdout_line(block, out_line)
+ # FIXME: Unlike HTTP, DRT dumps the content right after printing a Content-Length header.
+ # Don't wait until we're done with headers, just read the binary blob right now.
+ if content_length_before_header_check != block._content_length:
+ if block._content_length > 0:
+ block.content = self._server_process.read_stdout(deadline, block._content_length)
+ else:
+ driver._log.error("Received content of type %s with Content-Length of 0! This indicates a bug in %s.",
+ block.content_type, self._server_process.name())
+
+ if err_line:
+ if self._check_for_driver_crash(err_line):
+ break
+ if self._check_for_leak(err_line):
+ break
+ self.error_from_test += err_line
+
+ block.decode_content()
+ return block
+
+
+class ContentBlockStdin(driver.ContentBlock):
+ """Extends ContentBlock by adding another member variable that stores a path
+ for stdin.
+ """
+ def __init__(self):
+ self.stdin_path = None
+ super(ContentBlockStdin, self).__init__()

Powered by Google App Engine
This is Rietveld 408576698