2011-01-26 Dirk Pranke <dpranke@chromium.org>
[WebKit.git] / Tools / Scripts / webkitpy / layout_tests / port / mock_drt.py
1 #!/usr/bin/env python
2 # Copyright (C) 2011 Google Inc. All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
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
13 # distribution.
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.
17 #
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.
29
30 """
31 This is an implementation of the Port interface that overrides other
32 ports and changes the Driver binary to "MockDRT".
33 """
34
35 import logging
36 import optparse
37 import os
38 import sys
39
40 from webkitpy.layout_tests.port import base
41 from webkitpy.layout_tests.port import factory
42
43 _log = logging.getLogger(__name__)
44
45
46 class MockDRTPort(object):
47     """MockPort implementation of the Port interface."""
48
49     def __init__(self, **kwargs):
50         prefix = 'mock-'
51         if 'port_name' in kwargs:
52             if kwargs['port_name'].startswith(prefix):
53                 kwargs['port_name'] = kwargs['port_name'][len(prefix):]
54             else:
55                 kwargs['port_name'] = None
56         self.__delegate = factory.get(**kwargs)
57
58     def __getattr__(self, name):
59         return getattr(self.__delegate, name)
60
61     def check_build(self, needs_http):
62         return True
63
64     def check_sys_deps(self, needs_http):
65         return True
66
67     def driver_cmd_line(self):
68         driver = self.create_driver(0)
69         return driver.cmd_line()
70
71     def _path_to_driver(self):
72         return os.path.abspath(__file__)
73
74     def create_driver(self, worker_number):
75         # We need to create a driver object as the delegate would, but
76         # overwrite the path to the driver binary in its command line. We do
77         # this by actually overwriting its cmd_line() method with a proxy
78         # method that splices in the mock_drt path and command line arguments
79         # in place of the actual path to the driver binary.
80
81         # FIXME: This doesn't yet work for Chromium test_shell ports.
82         def overriding_cmd_line():
83             cmd = self.__original_driver_cmd_line()
84             index = cmd.index(self.__delegate._path_to_driver())
85             cmd[index:index + 1] = [sys.executable, self._path_to_driver(),
86                                     '--platform', self.name()]
87             return cmd
88
89         delegated_driver = self.__delegate.create_driver(worker_number)
90         self.__original_driver_cmd_line = delegated_driver.cmd_line
91         delegated_driver.cmd_line = overriding_cmd_line
92         return delegated_driver
93
94     def start_helper(self):
95         pass
96
97     def start_http_server(self):
98         pass
99
100     def start_websocket_server(self):
101         pass
102
103     def stop_helper(self):
104         pass
105
106     def stop_http_server(self):
107         pass
108
109     def stop_websocket_server(self):
110         pass
111
112
113 def main(argv, stdin, stdout, stderr):
114     """Run the tests."""
115
116     options, args = parse_options(argv)
117     drt = MockDRT(options, args, stdin, stdout, stderr)
118     return drt.run()
119
120
121 def parse_options(argv):
122     # FIXME: We need to figure out how to handle variants that have
123     # different command-line conventions.
124     option_list = [
125         optparse.make_option('--platform', action='store',
126                              help='platform to emulate'),
127         optparse.make_option('--layout-tests', action='store_true',
128                              default=True, help='run layout tests'),
129         optparse.make_option('--pixel-tests', action='store_true',
130                              default=False,
131                              help='output image for pixel tests'),
132     ]
133     option_parser = optparse.OptionParser(option_list=option_list)
134     return option_parser.parse_args(argv)
135
136
137 class MockDRT(object):
138     def __init__(self, options, args, stdin, stdout, stderr):
139         self._options = options
140         self._args = args
141         self._stdout = stdout
142         self._stdin = stdin
143         self._stderr = stderr
144
145         port_name = None
146         if options.platform:
147             port_name = options.platform
148         self._port = factory.get(port_name, options=options)
149         self._exit_status = 0
150
151     def run(self):
152         try:
153             while True:
154                 line = self._stdin.readline()
155                 if not line:
156                     break
157
158                 url, expected_checksum = self.parse_input(line)
159                 self.run_one_test(url, expected_checksum)
160         except ValueError, e:
161             self._stderr.write("MockDRT exiting, ValueError raised: '%s'\n"
162                                % str(e))
163             self._exit_status = 1
164         except Exception, e:
165             self._stderr.write("MockDRT exiting, unexpected exception: '%s'\n"
166                                % str(e))
167             self._exit_status = -1
168
169         return self._exit_status
170
171     def parse_input(self, line):
172         line = line.strip()
173         if "'" in line:
174             return line.split("'", 1)
175         return (line, None)
176
177     def run_one_test(self, url, expected_checksum):
178         port = self._port
179         if url.startswith('file:///') or url.startswith('http'):
180             test_name = port.uri_to_test_name(url)
181             test_path = port.path_from_webkit_base('LayoutTests', test_name)
182         else:
183             test_path = url
184
185         actual_text = port.expected_text(test_path)
186         if self._options.pixel_tests and expected_checksum:
187             actual_checksum = port.expected_checksum(test_path)
188             actual_image = port.expected_image(test_path)
189
190         self._stdout.write("Content-Type: text/plain\n")
191         self._stdout.write(actual_text)
192         self._stdout.write("#EOF\n")
193
194         if self._options.pixel_tests and expected_checksum:
195             self._stdout.write("\n")
196             self._stdout.write("ActualHash: %s\n" % actual_checksum)
197             self._stdout.write("ExpectedHash: %s\n" % expected_checksum)
198             if actual_checksum != expected_checksum:
199                 self._stdout.write("Content-Length: %s\n\n" % len(actual_image))
200                 self._stdout.write(actual_image)
201         self._stdout.write("#EOF\n")
202         self._stdout.flush()
203         self._stderr.flush()
204
205
206 if __name__ == '__main__':
207     sys.exit(main(sys.argv[1:], sys.stdin, sys.stdout, sys.stderr))