2 # Copyright (C) 2011 Google Inc. All rights reserved.
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
14 # * Neither the Google name nor the names of its
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 This is an implementation of the Port interface that overrides other
32 ports and changes the Driver binary to "MockDRT".
41 from webkitpy.common.system import filesystem
43 from webkitpy.layout_tests.port import base
44 from webkitpy.layout_tests.port import factory
46 _log = logging.getLogger(__name__)
49 class MockDRTPort(object):
50 """MockPort implementation of the Port interface."""
52 def __init__(self, **kwargs):
54 if 'port_name' in kwargs:
55 kwargs['port_name'] = kwargs['port_name'][len(prefix):]
56 self.__delegate = factory.get(**kwargs)
57 self.__real_name = prefix + self.__delegate.name()
60 return self.__real_name
62 def __getattr__(self, name):
63 return getattr(self.__delegate, name)
65 def acquire_http_lock(self):
68 def release_http_lock(self):
71 def check_build(self, needs_http):
74 def check_sys_deps(self, needs_http):
77 def driver_cmd_line(self):
78 driver = self.create_driver(0)
79 return driver.cmd_line()
81 def _path_to_driver(self):
82 return os.path.abspath(__file__)
84 def create_driver(self, worker_number):
85 # We need to create a driver object as the delegate would, but
86 # overwrite the path to the driver binary in its command line. We do
87 # this by actually overwriting its cmd_line() method with a proxy
88 # method that splices in the mock_drt path and command line arguments
89 # in place of the actual path to the driver binary.
91 def overriding_cmd_line():
92 cmd = self.__original_driver_cmd_line()
93 index = cmd.index(self.__delegate._path_to_driver())
94 cmd[index:index + 1] = [sys.executable, self._path_to_driver(),
95 '--platform', self.name()]
98 delegated_driver = self.__delegate.create_driver(worker_number)
99 self.__original_driver_cmd_line = delegated_driver.cmd_line
100 delegated_driver.cmd_line = overriding_cmd_line
101 return delegated_driver
103 def start_helper(self):
106 def start_http_server(self):
109 def start_websocket_server(self):
112 def stop_helper(self):
115 def stop_http_server(self):
118 def stop_websocket_server(self):
122 def main(argv, fs, stdin, stdout, stderr):
125 options, args = parse_options(argv)
127 drt = MockChromiumDRT(options, args, fs, stdin, stdout, stderr)
129 drt = MockDRT(options, args, fs, stdin, stdout, stderr)
133 def parse_options(argv):
134 # FIXME: We have to do custom arg parsing instead of using the optparse
135 # module. First, Chromium and non-Chromium DRTs have a different argument
136 # syntax. Chromium uses --pixel-tests=<path>, and non-Chromium uses
137 # --pixel-tests as a boolean flag. Second, we don't want to have to list
138 # every command line flag DRT accepts, but optparse complains about
139 # unrecognized flags. At some point it might be good to share a common
140 # DRT options class between this file and webkit.py and chromium.py
141 # just to get better type checking.
142 platform_index = argv.index('--platform')
143 platform = argv[platform_index + 1]
148 if platform.startswith('chromium'):
151 if arg.startswith('--pixel-tests'):
153 pixel_path = arg[len('--pixel-tests='):]
155 pixel_tests = '--pixel-tests' in argv
156 options = base.DummyOptions(chromium=chromium,
158 pixel_tests=pixel_tests,
159 pixel_path=pixel_path)
163 # FIXME: Should probably change this to use DriverInput after
164 # https://bugs.webkit.org/show_bug.cgi?id=53004 lands.
165 class _DRTInput(object):
166 def __init__(self, line):
167 vals = line.strip().split("'")
173 self.checksum = vals[1]
176 class MockDRT(object):
177 def __init__(self, options, args, filesystem, stdin, stdout, stderr):
178 self._options = options
180 self._filesystem = filesystem
181 self._stdout = stdout
183 self._stderr = stderr
187 port_name = options.platform
188 self._port = factory.get(port_name, options=options, filesystem=filesystem)
192 line = self._stdin.readline()
195 self.run_one_test(self.parse_input(line))
198 def parse_input(self, line):
199 return _DRTInput(line)
201 def run_one_test(self, test_input):
203 if test_input.uri.startswith('http'):
204 test_name = port.uri_to_test_name(test_input.uri)
205 test_path = self._filesystem.join(port.layout_tests_dir(), test_name)
207 test_path = test_input.uri
209 actual_text = port.expected_text(test_path)
210 actual_audio = port.expected_audio(test_path)
211 if self._options.pixel_tests and test_input.checksum:
212 actual_checksum = port.expected_checksum(test_path)
213 actual_image = port.expected_image(test_path)
216 self._stdout.write('Content-Type: audio/wav\n')
217 self._stdout.write('Content-Transfer-Encoding: base64\n')
218 output = base64.b64encode(actual_audio)
219 self._stdout.write('Content-Length: %s\n' % len(output))
220 self._stdout.write(output)
222 self._stdout.write('Content-Type: text/plain\n')
223 # FIXME: Note that we don't ensure there is a trailing newline!
224 # This mirrors actual (Mac) DRT behavior but is a bug.
225 self._stdout.write(actual_text)
227 self._stdout.write('#EOF\n')
229 if self._options.pixel_tests and test_input.checksum:
230 self._stdout.write('\n')
231 self._stdout.write('ActualHash: %s\n' % actual_checksum)
232 self._stdout.write('ExpectedHash: %s\n' % test_input.checksum)
233 if actual_checksum != test_input.checksum:
234 self._stdout.write('Content-Type: image/png\n')
235 self._stdout.write('Content-Length: %s\n' % len(actual_image))
236 self._stdout.write(actual_image)
237 self._stdout.write('#EOF\n')
242 # FIXME: Should probably change this to use DriverInput after
243 # https://bugs.webkit.org/show_bug.cgi?id=53004 lands.
244 class _ChromiumDRTInput(_DRTInput):
245 def __init__(self, line):
246 vals = line.strip().split()
248 self.uri, self.timeout, self.checksum = vals
251 self.timeout = vals[1]
255 class MockChromiumDRT(MockDRT):
256 def parse_input(self, line):
257 return _ChromiumDRTInput(line)
259 def run_one_test(self, test_input):
261 test_name = self._port.uri_to_test_name(test_input.uri)
262 test_path = self._filesystem.join(port.layout_tests_dir(), test_name)
264 actual_text = port.expected_text(test_path)
267 if self._options.pixel_tests and test_input.checksum:
268 actual_checksum = port.expected_checksum(test_path)
269 if actual_checksum != test_input.checksum:
270 actual_image = port.expected_image(test_path)
272 self._stdout.write("#URL:%s\n" % test_input.uri)
273 if self._options.pixel_tests and test_input.checksum:
274 self._stdout.write("#MD5:%s\n" % actual_checksum)
275 self._filesystem.write_binary_file(self._options.pixel_path,
277 self._stdout.write(actual_text)
279 # FIXME: (See above FIXME as well). Chromium DRT appears to always
280 # ensure the text output has a trailing newline. Mac DRT does not.
281 if not actual_text.endswith('\n'):
282 self._stdout.write('\n')
283 self._stdout.write('#EOF\n')
287 if __name__ == '__main__':
288 fs = filesystem.FileSystem()
289 sys.exit(main(sys.argv[1:], fs, sys.stdin, sys.stdout, sys.stderr))