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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright (C) 2014 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 # * Neither the Google name nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 from webkitpy.layout_tests.port import driver
30 import time
31
32
33 class BrowserTestDriver(driver.Driver):
34 """Object for running print preview test(s) using browser_tests."""
35 def __init__(self, port, worker_number, pixel_tests, no_timeout=False):
36 """Invokes the constructor of driver.Driver."""
37 super(BrowserTestDriver, self).__init__(port, worker_number, pixel_tests , no_timeout)
38
39 def start(self, pixel_tests, per_test_args, deadline):
40 """Same as Driver.start() however, it has an extra step. It waits for
41 a path to a file to be used for stdin to be printed by the browser test.
42 If a path is found by the deadline test test will open the file and
43 assign it to the stdin of the process that is owned by this driver's
44 server process.
45 """
46 # FIXME(ivandavid): Need to handle case where the layout test doesn't
47 # get a file name.
48 new_cmd_line = self.cmd_line(pixel_tests, per_test_args)
49 if not self._server_process or new_cmd_line != self._current_cmd_line:
50 self._start(pixel_tests, per_test_args)
51 self._run_post_start_tasks()
52 path, found = self._read_stdin_path(time.time() + int(deadline) / 10 00.0)
53 if found:
54 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
55
56 def cmd_line(self, pixel_tests, per_test_args):
57 """Command line arguments to run the browser test."""
58 cmd = self._command_wrapper(self._port.get_option('wrapper'))
59 cmd.append(self._port._path_to_driver())
60 cmd.append('--gtest_filter=PrintPreviewPdfGeneratedBrowserTest.MANUAL_Du mmyTest')
61 cmd.append('--run-manual')
62 cmd.append('--single_process')
63 cmd.extend(per_test_args)
64 return cmd
65
66 def run_test(self, driver_input, stop_when_done):
67 """Run a single test and return the results.
68
69 Note that it is okay if a test times out or crashes and leaves
70 the driver in an indeterminate state. The upper layers of the program
71 are responsible for cleaning up and ensuring things are okay.
72
73 Returns a DriverOutput object.
74
75 This function was overriden because the new start function had to be
76 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.
77 """
78 start_time = time.time()
79 self.start(driver_input.should_run_pixel_test, driver_input.args, int(dr iver_input.timeout))
80 test_begin_time = time.time()
81 self.error_from_test = str()
82 self.err_seen_eof = False
83
84 command = self._command_from_driver_input(driver_input)
85 deadline = test_begin_time + int(driver_input.timeout) / 1000.0
86
87 self._server_process.write(command)
88 text, audio = self._read_first_block(deadline) # First block is either text or audio
89 image, actual_image_hash = self._read_optional_image_block(deadline) # The second (optional) block is image data.
90
91 crashed = self.has_crashed()
92 timed_out = self._server_process.timed_out
93 pid = self._server_process.pid()
94 leaked = self._leaked
95
96 if stop_when_done or crashed or timed_out or leaked:
97 # We call stop() even if we crashed or timed out in order to get any remaining stdout/stderr output.
98 # In the timeout case, we kill the hung process as well.
99 out, err = self._server_process.stop(self._port.driver_stop_timeout( ) if stop_when_done else 0.0)
100 if out:
101 text += out
102 if err:
103 self.error_from_test += err
104 self._server_process = None
105
106 crash_log = None
107 if crashed:
108 self.error_from_test, crash_log = self._get_crash_log(text, self.err or_from_test, newer_than=start_time)
109
110 # If we don't find a crash log use a placeholder error message inste ad.
111 if not crash_log:
112 pid_str = str(self._crashed_pid) if self._crashed_pid else "unkn own pid"
113 crash_log = 'No crash log found for %s:%s.\n' % (self._crashed_p rocess_name, pid_str)
114 # If we were unresponsive append a message informing there may n ot have been a crash.
115 if self._subprocess_was_unresponsive:
116 crash_log += 'Process failed to become responsive before tim ing out.\n'
117
118 # Print stdout and stderr to the placeholder crash log; we want as much context as possible.
119 if self.error_from_test:
120 crash_log += '\nstdout:\n%s\nstderr:\n%s\n' % (text, self.er ror_from_test)
121 return driver.DriverOutput(text, image, actual_image_hash, audio,
122 crash=crashed, test_time=time.time() - test_begin_time, measurements =self._measurements,
123 timeout=timed_out, error=self.error_from_test,
124 crashed_process_name=self._crashed_process_name,
125 crashed_pid=self._crashed_pid, crash_log=crash_log,
126 leak=leaked, leak_log=self._leak_log,
127 pid=pid)
128
129 def _read_stdin_path(self, deadline):
130 """Reads the file path to be used for stdin."""
131 block = self._read_block(deadline)
132 if block.stdin_path:
133 return (block.stdin_path, True)
134 return (None, False)
135
136 def _process_stdout_line(self, block, line):
137 """Additional header read to look for the stdin path."""
138 if (self._read_header(block, line, 'StdinPath: ', 'stdin_path')):
139 return
140 super(BrowserTestDriver, self)._process_stdout_line(block, line)
141
142 def _read_block(self, deadline, wait_for_stderr_eof=False):
143 """Same as Driver._read_block() however rather than using ContentBlock,
144 ContentBlockStdin is used, as ContentBlock does not have the member
145 variable to store the stdin path.
146 """
147 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.
148 out_seen_eof = False
149
150 while not self.has_crashed():
151 if out_seen_eof and (self.err_seen_eof or not wait_for_stderr_eof):
152 break
153
154 if self.err_seen_eof:
155 out_line = self._server_process.read_stdout_line(deadline)
156 err_line = None
157 elif out_seen_eof:
158 out_line = None
159 err_line = self._server_process.read_stderr_line(deadline)
160 else:
161 out_line, err_line = self._server_process.read_either_stdout_or_ stderr_line(deadline)
162 if self._server_process.timed_out or self.has_crashed():
163 break
164
165 if out_line:
166 assert not out_seen_eof
167 out_line, out_seen_eof = self._strip_eof(out_line)
168 if err_line:
169 assert not self.err_seen_eof
170 err_line, self.err_seen_eof = self._strip_eof(err_line)
171
172 if out_line:
173 if out_line[-1] != "\n":
174 driver._log.error("Last character read from DRT stdout line was not a newline! This indicates either a NRWT or DRT bug.")
175 content_length_before_header_check = block._content_length
176 self._process_stdout_line(block, out_line)
177 # FIXME: Unlike HTTP, DRT dumps the content right after printing a Content-Length header.
178 # Don't wait until we're done with headers, just read the binary blob right now.
179 if content_length_before_header_check != block._content_length:
180 if block._content_length > 0:
181 block.content = self._server_process.read_stdout(deadlin e, block._content_length)
182 else:
183 driver._log.error("Received content of type %s with Cont ent-Length of 0! This indicates a bug in %s.",
184 block.content_type, self._server_process.name ())
185
186 if err_line:
187 if self._check_for_driver_crash(err_line):
188 break
189 if self._check_for_leak(err_line):
190 break
191 self.error_from_test += err_line
192
193 block.decode_content()
194 return block
195
196
197 class ContentBlockStdin(driver.ContentBlock):
198 """Extends ContentBlock by adding another member variable that stores a path
199 for stdin.
200 """
201 def __init__(self):
202 self.stdin_path = None
203 super(ContentBlockStdin, self).__init__()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698