[WinCairo] httpd service install needs to precede server start
[WebKit-https.git] / Tools / Scripts / webkitpy / port / mock_drt.py
1 # Copyright (c) 2012 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 """
30 This is an implementation of the Port interface that overrides other
31 ports and changes the Driver binary to "MockDRT".
32
33 The MockDRT objects emulate what a real DRT would do. In particular, they
34 return the output a real DRT would return for a given test, assuming that
35 test actually passes (except for reftests, which currently cause the
36 MockDRT to crash).
37 """
38
39 import base64
40 import logging
41 import optparse
42 import os
43 import sys
44
45 # Since we execute this script directly as part of the unit tests, we need to ensure
46 # that Tools/Scripts is in sys.path for the next imports to work correctly.
47 script_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
48 if script_dir not in sys.path:
49     sys.path.append(script_dir)
50
51 from webkitpy.common.system.systemhost import SystemHost
52 from webkitpy.port.driver import DriverInput, DriverOutput, DriverProxy
53 from webkitpy.port.factory import PortFactory
54
55 _log = logging.getLogger(__name__)
56
57
58 class MockDRTPort(object):
59     port_name = 'mock'
60
61     @classmethod
62     def determine_full_port_name(cls, host, options, port_name):
63         return port_name
64
65     def __init__(self, host, port_name, **kwargs):
66         self.__delegate = PortFactory(host).get(port_name.replace('mock-', ''), **kwargs)
67
68     def __getattr__(self, name):
69         return getattr(self.__delegate, name)
70
71     def check_build(self):
72         return True
73
74     def check_sys_deps(self):
75         return True
76
77     def create_driver(self, worker_number, no_timeout=False):
78         # The magic of the MockDRTPort is that we create a driver that has a
79         # cmd_line() method monkey-patched to invoke this script instead of DRT.
80         return DriverProxy(self, worker_number, self._mocked_driver_maker, pixel_tests=self.get_option('pixel_tests'), no_timeout=no_timeout)
81
82     @staticmethod
83     def _mocked_driver_maker(port, worker_number, pixel_tests, no_timeout=False):
84         path_to_this_file = port.host.filesystem.abspath(__file__.replace('.pyc', '.py'))
85         driver = port.__delegate._driver_class()(port, worker_number, pixel_tests, no_timeout)
86         driver.cmd_line = port._overriding_cmd_line(driver.cmd_line,
87                                                     port.__delegate._path_to_driver(),
88                                                     sys.executable,
89                                                     path_to_this_file,
90                                                     port.__delegate.name())
91         return driver
92
93     @staticmethod
94     def _overriding_cmd_line(original_cmd_line, driver_path, python_exe, this_file, port_name):
95         def new_cmd_line(pixel_tests, per_test_args):
96             cmd_line = original_cmd_line(pixel_tests, per_test_args)
97             index = cmd_line.index(driver_path)
98             cmd_line[index:index + 1] = [python_exe, this_file, '--platform', port_name]
99             return cmd_line
100
101         return new_cmd_line
102
103     def start_helper(self, pixel_tests=False):
104         pass
105
106     def start_http_server(self, number_of_servers):
107         pass
108
109     def start_websocket_server(self):
110         pass
111
112     def stop_helper(self):
113         pass
114
115     def stop_http_server(self):
116         pass
117
118     def stop_websocket_server(self):
119         pass
120
121     def show_results_html_file(self, results_filename):
122         pass
123
124
125 def main(argv, host, stdin, stdout, stderr):
126     """Run the tests."""
127
128     options, args = parse_options(argv)
129     drt = MockDRT(options, args, host, stdin, stdout, stderr)
130     return drt.run()
131
132
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]
144
145     pixel_tests = '--pixel-tests' in argv
146     return (optparse.Values({'platform': platform, 'pixel_tests': pixel_tests}), argv)
147
148
149 class MockDRT(object):
150     def __init__(self, options, args, host, stdin, stdout, stderr):
151         self._options = options
152         self._args = args
153         self._host = host
154         self._stdout = stdout
155         self._stdin = stdin
156         self._stderr = stderr
157
158         port_name = None
159         if options.platform:
160             port_name = options.platform
161         self._port = PortFactory(host).get(port_name=port_name, options=options)
162         self._driver = self._port.create_driver(0)
163
164     def run(self):
165         while True:
166             line = self._stdin.readline()
167             if not line:
168                 return 0
169             driver_input = self.input_from_line(line)
170             dirname, basename = self._port.split_test(driver_input.test_name)
171             is_reftest = (self._port.reference_files(driver_input.test_name) or
172                           self._port.is_reference_html_file(self._port._filesystem, dirname, basename))
173             output = self.output_for_test(driver_input, is_reftest)
174             self.write_test_output(driver_input, output, is_reftest)
175
176     def input_from_line(self, line):
177         vals = line.strip().split("'")
178         if len(vals) == 1:
179             uri = vals[0]
180             checksum = None
181         else:
182             uri = vals[0]
183             checksum = vals[1]
184         if uri.startswith('http://') or uri.startswith('https://'):
185             test_name = self._driver.uri_to_test(uri)
186         else:
187             test_name = self._port.relative_test_filename(uri)
188
189         return DriverInput(test_name, 0, checksum, self._options.pixel_tests)
190
191     def output_for_test(self, test_input, is_reftest):
192         port = self._port
193         actual_text = port.expected_text(test_input.test_name)
194         actual_audio = port.expected_audio(test_input.test_name)
195         actual_image = None
196         actual_checksum = None
197         if is_reftest:
198             # Make up some output for reftests.
199             actual_text = 'reference text\n'
200             actual_checksum = 'mock-checksum'
201             actual_image = 'blank'
202             if test_input.test_name.endswith('-mismatch.html'):
203                 actual_text = 'not reference text\n'
204                 actual_checksum = 'not-mock-checksum'
205                 actual_image = 'not blank'
206         elif self._options.pixel_tests and test_input.image_hash:
207             actual_checksum = port.expected_checksum(test_input.test_name)
208             actual_image = port.expected_image(test_input.test_name)
209
210         return DriverOutput(actual_text, actual_image, actual_checksum, actual_audio)
211
212     def write_test_output(self, test_input, output, is_reftest):
213         if output.audio:
214             self._stdout.write('Content-Type: audio/wav\n')
215             self._stdout.write('Content-Transfer-Encoding: base64\n')
216             self._stdout.write(base64.b64encode(output.audio))
217         else:
218             self._stdout.write('Content-Type: text/plain\n')
219             # FIXME: Note that we don't ensure there is a trailing newline!
220             # This mirrors actual (Mac) DRT behavior but is a bug.
221             if output.text:
222                 self._stdout.write(output.text)
223
224         self._stdout.write('#EOF\n')
225
226         if self._options.pixel_tests and output.image_hash:
227             self._stdout.write('\n')
228             self._stdout.write('ActualHash: %s\n' % output.image_hash)
229             self._stdout.write('ExpectedHash: %s\n' % test_input.image_hash)
230             if output.image_hash != test_input.image_hash:
231                 self._stdout.write('Content-Type: image/png\n')
232                 self._stdout.write('Content-Length: %s\n' % len(output.image))
233                 self._stdout.write(output.image)
234         self._stdout.write('#EOF\n')
235         self._stdout.flush()
236         self._stderr.write('#EOF\n')
237         self._stderr.flush()
238
239 if __name__ == '__main__':
240     # Note that the Mock in MockDRT refers to the fact that it is emulating a
241     # real DRT, and as such, it needs access to a real SystemHost, not a MockSystemHost.
242     sys.exit(main(sys.argv[1:], SystemHost(), sys.stdin, sys.stdout, sys.stderr))