1dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#!/usr/bin/env python 2dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# Copyright (C) 2010 Google Inc. All rights reserved. 35abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick# Copyright (C) 2010 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>, University of Szeged 4dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# 5dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# Redistribution and use in source and binary forms, with or without 6dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# modification, are permitted provided that the following conditions are 7dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# met: 8dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# 9dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# * Redistributions of source code must retain the above copyright 10dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# notice, this list of conditions and the following disclaimer. 11dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# * Redistributions in binary form must reproduce the above 12dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# copyright notice, this list of conditions and the following disclaimer 13dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# in the documentation and/or other materials provided with the 14dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# distribution. 15dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# * Neither the Google name nor the names of its 16dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# contributors may be used to endorse or promote products derived from 17dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# this software without specific prior written permission. 18dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# 19dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 31dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block"""WebKit implementations of the Port interface.""" 32dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 332daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochimport base64 34dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport logging 35ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochimport operator 36dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport os 37dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport re 38dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport signal 39dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport sys 40dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport time 41dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport webbrowser 42dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 432fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockfrom webkitpy.common.system import ospath 442fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockfrom webkitpy.layout_tests.port import base 452fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockfrom webkitpy.layout_tests.port import server_process 46dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 47dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block_log = logging.getLogger("webkitpy.layout_tests.port.webkit") 48dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 49dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 50dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockclass WebKitPort(base.Port): 51dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block """WebKit implementation of the Port class.""" 52dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 53bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen def __init__(self, **kwargs): 54bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen base.Port.__init__(self, **kwargs) 55dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block self._cached_apache_path = None 56dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 57dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # FIXME: disable pixel tests until they are run by default on the 58dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # build machines. 592fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if not hasattr(self._options, "pixel_tests") or self._options.pixel_tests == None: 602fc2651226baac27029e38c9d6ef883fa32084dbSteve Block self._options.pixel_tests = False 61dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 62dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def baseline_path(self): 63dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return self._webkit_baseline_path(self._name) 64dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 65dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def baseline_search_path(self): 66dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return [self._webkit_baseline_path(self._name)] 67dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 68dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def path_to_test_expectations_file(self): 69ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch return self._filesystem.join(self._webkit_baseline_path(self._name), 70ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 'test_expectations.txt') 71dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 72dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _build_driver(self): 736b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner configuration = self.get_option('configuration') 746b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner return self._config.build_dumprendertree(configuration) 75dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 76dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _check_driver(self): 77dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block driver_path = self._path_to_driver() 78ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if not self._filesystem.exists(driver_path): 79dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block _log.error("DumpRenderTree was not found at %s" % driver_path) 80dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return False 81dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return True 82dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 83dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def check_build(self, needs_http): 84a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if self.get_option('build') and not self._build_driver(): 85dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return False 86dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if not self._check_driver(): 87dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return False 88a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if self.get_option('pixel_tests'): 89dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if not self.check_image_diff(): 90dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return False 91dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if not self._check_port_build(): 92dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return False 93dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return True 94dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 95dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _check_port_build(self): 96dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # Ports can override this method to do additional checks. 97dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return True 98dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 99dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def check_image_diff(self, override_step=None, logging=True): 100dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block image_diff_path = self._path_to_image_diff() 101ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if not self._filesystem.exists(image_diff_path): 102dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block _log.error("ImageDiff was not found at %s" % image_diff_path) 103dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return False 104dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return True 105dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 106bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen def diff_image(self, expected_contents, actual_contents, 107e14391e94c850b8bd03680c23b38978db68687a8John Reck diff_filename=None): 108dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block """Return True if the two files are different. Also write a delta 109dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block image of the two images into |diff_filename| if it is not None.""" 110dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 111dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # Handle the case where the test didn't actually generate an image. 1122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch # FIXME: need unit tests for this. 1132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if not actual_contents and not expected_contents: 1142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return False 1152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if not actual_contents or not expected_contents: 116dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return True 117dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 118e14391e94c850b8bd03680c23b38978db68687a8John Reck sp = self._diff_image_request(expected_contents, actual_contents) 119bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen return self._diff_image_reply(sp, diff_filename) 120dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 121e14391e94c850b8bd03680c23b38978db68687a8John Reck def _diff_image_request(self, expected_contents, actual_contents): 1222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block # FIXME: There needs to be a more sane way of handling default 1232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block # values for options so that you can distinguish between a default 1242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block # value of None and a default value that wasn't set. 125e14391e94c850b8bd03680c23b38978db68687a8John Reck if self.get_option('tolerance') is not None: 126e14391e94c850b8bd03680c23b38978db68687a8John Reck tolerance = self.get_option('tolerance') 127e14391e94c850b8bd03680c23b38978db68687a8John Reck else: 128e14391e94c850b8bd03680c23b38978db68687a8John Reck tolerance = 0.1 129e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke command = [self._path_to_image_diff(), '--tolerance', str(tolerance)] 130dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block sp = server_process.ServerProcess(self, 'ImageDiff', command) 131dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 132dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block sp.write('Content-Length: %d\n%sContent-Length: %d\n%s' % 133bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen (len(actual_contents), actual_contents, 134bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen len(expected_contents), expected_contents)) 135dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 136dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return sp 137dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 138bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen def _diff_image_reply(self, sp, diff_filename): 139dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block timeout = 2.0 140dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block deadline = time.time() + timeout 141dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block output = sp.read_line(timeout) 142dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block while not sp.timed_out and not sp.crashed and output: 143dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if output.startswith('Content-Length'): 144dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block m = re.match('Content-Length: (\d+)', output) 145dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block content_length = int(m.group(1)) 146dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block timeout = deadline - time.time() 147dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block output = sp.read(timeout, content_length) 148dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block break 149dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block elif output.startswith('diff'): 150dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block break 151dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block else: 152dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block timeout = deadline - time.time() 153dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block output = sp.read_line(deadline) 154dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 155dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block result = True 156dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if output.startswith('diff'): 157dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block m = re.match('diff: (.+)% (passed|failed)', output) 158dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if m.group(2) == 'passed': 159dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block result = False 160dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block elif output and diff_filename: 1612fc2651226baac27029e38c9d6ef883fa32084dbSteve Block self._filesystem.write_binary_file(diff_filename, output) 162dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block elif sp.timed_out: 163bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen _log.error("ImageDiff timed out") 164dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block elif sp.crashed: 165dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block _log.error("ImageDiff crashed") 166dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block sp.stop() 167dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return result 168dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 1692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch def default_results_directory(self): 170dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # Results are store relative to the built products to make it easy 171dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # to have multiple copies of webkit checked out and built. 1722daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return self._build_path('layout-test-results') 173dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 174dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def setup_test_run(self): 175dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # This port doesn't require any specific configuration. 176dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block pass 177dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 1784576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang def create_driver(self, worker_number): 1794576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang return WebKitDriver(self, worker_number) 180dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 181dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _tests_for_other_platforms(self): 1822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch # By default we will skip any directory under LayoutTests/platform 1832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch # that isn't in our baseline search path (this mirrors what 1842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch # old-run-webkit-tests does in findTestsToRun()). 1852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch # Note this returns LayoutTests/platform/*, not platform/*/*. 1862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch entries = self._filesystem.glob(self._webkit_baseline_path('*')) 1872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch dirs_to_skip = [] 1882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch for entry in entries: 1892daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if self._filesystem.isdir(entry) and not entry in self.baseline_search_path(): 1902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch basename = self._filesystem.basename(entry) 1912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch dirs_to_skip.append('platform/%s' % basename) 1922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return dirs_to_skip 193dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 1945abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick def _runtime_feature_list(self): 1955abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick """Return the supported features of DRT. If a port doesn't support 1965abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick this DRT switch, it has to override this method to return None""" 1975abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick driver_path = self._path_to_driver() 1985abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick feature_list = ' '.join(os.popen(driver_path + " --print-supported-features 2>&1").readlines()) 1995abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick if "SupportedFeatures:" in feature_list: 2005abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return feature_list 2015abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return None 2025abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick 2035abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick def _supported_symbol_list(self): 2045abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick """Return the supported symbols of WebCore.""" 2055abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick webcore_library_path = self._path_to_webcore_library() 2065abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick if not webcore_library_path: 2075abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return None 2085abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick symbol_list = ' '.join(os.popen("nm " + webcore_library_path).readlines()) 2095abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return symbol_list 2105abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick 2115abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick def _directories_for_features(self): 2125abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick """Return the supported feature dictionary. The keys are the 2135abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick features and the values are the directories in lists.""" 2145abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick directories_for_features = { 2155abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick "Accelerated Compositing": ["compositing"], 2165abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick "3D Rendering": ["animations/3d", "transforms/3d"], 2175abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick } 2185abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return directories_for_features 2195abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick 2205abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick def _directories_for_symbols(self): 2215abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick """Return the supported feature dictionary. The keys are the 2225abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick symbols and the values are the directories in lists.""" 2235abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick directories_for_symbol = { 2245abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick "MathMLElement": ["mathml"], 2255abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick "GraphicsLayer": ["compositing"], 2265abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick "WebCoreHas3DRendering": ["animations/3d", "transforms/3d"], 227bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen "WebGLShader": ["fast/canvas/webgl", "compositing/webgl", "http/tests/canvas/webgl"], 2285abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick "WMLElement": ["http/tests/wml", "fast/wml", "wml"], 2295abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick "parseWCSSInputProperty": ["fast/wcss"], 2305abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick "isXHTMLMPDocument": ["fast/xhtmlmp"], 2315abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick } 2325abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return directories_for_symbol 2335abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick 2345abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick def _skipped_tests_for_unsupported_features(self): 2355abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick """Return the directories of unsupported tests. Search for the 2365abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick symbols in the symbol_list, if found add the corresponding 2375abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick directories to the skipped directory list.""" 2385abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick feature_list = self._runtime_feature_list() 2395abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick directories = self._directories_for_features() 2405abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick 2415abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick # if DRT feature detection not supported 2425abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick if not feature_list: 2435abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick feature_list = self._supported_symbol_list() 2445abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick directories = self._directories_for_symbols() 2455abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick 2465abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick if not feature_list: 2475abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return [] 2485abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick 2495abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick skipped_directories = [directories[feature] 2505abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick for feature in directories.keys() 2515abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick if feature not in feature_list] 2525abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return reduce(operator.add, skipped_directories) 2535abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick 254dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _tests_for_disabled_features(self): 255dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # FIXME: This should use the feature detection from 256dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # webkitperl/features.pm to match run-webkit-tests. 257dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # For now we hard-code a list of features known to be disabled on 258dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # the Mac platform. 259dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block disabled_feature_tests = [ 260dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block "fast/xhtmlmp", 261dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block "http/tests/wml", 262dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block "mathml", 263dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block "wml", 264dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block ] 265dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # FIXME: webarchive tests expect to read-write from 266dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # -expected.webarchive files instead of .txt files. 267dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # This script doesn't know how to do that yet, so pretend they're 268dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # just "disabled". 269dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block webarchive_tests = [ 270dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block "webarchive", 271dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block "svg/webarchive", 272dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block "http/tests/webarchive", 273dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block "svg/custom/image-with-prefix-in-webarchive.svg", 274dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block ] 2755abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick unsupported_feature_tests = self._skipped_tests_for_unsupported_features() 2765abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return disabled_feature_tests + webarchive_tests + unsupported_feature_tests 277dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 2782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block def _tests_from_skipped_file_contents(self, skipped_file_contents): 279dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block tests_to_skip = [] 2802fc2651226baac27029e38c9d6ef883fa32084dbSteve Block for line in skipped_file_contents.split('\n'): 281dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block line = line.strip() 282dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if line.startswith('#') or not len(line): 283dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block continue 284dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block tests_to_skip.append(line) 285dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return tests_to_skip 286dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 287dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _skipped_file_paths(self): 288ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch return [self._filesystem.join(self._webkit_baseline_path(self._name), 'Skipped')] 289dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 290dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _expectations_from_skipped_files(self): 291dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block tests_to_skip = [] 292dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block for filename in self._skipped_file_paths(): 293ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if not self._filesystem.exists(filename): 294dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block _log.warn("Failed to open Skipped file: %s" % filename) 295dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block continue 2962fc2651226baac27029e38c9d6ef883fa32084dbSteve Block skipped_file_contents = self._filesystem.read_text_file(filename) 2972fc2651226baac27029e38c9d6ef883fa32084dbSteve Block tests_to_skip.extend(self._tests_from_skipped_file_contents(skipped_file_contents)) 298dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return tests_to_skip 299dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 300dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def test_expectations(self): 301dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # The WebKit mac port uses a combination of a test_expectations file 302dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # and 'Skipped' files. 30321939df44de1705786c545cd1bf519d47250322dBen Murdoch expectations_path = self.path_to_test_expectations_file() 304ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch return self._filesystem.read_text_file(expectations_path) + self._skips() 305dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 306dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _skips(self): 307dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # Each Skipped file contains a list of files 308dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # or directories to be skipped during the test run. The total list 309dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # of tests to skipped is given by the contents of the generic 310dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # Skipped file found in platform/X plus a version-specific file 311dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # found in platform/X-version. Duplicate entries are allowed. 312dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # This routine reads those files and turns contents into the 313dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # format expected by test_expectations. 314dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 3155abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick tests_to_skip = self.skipped_layout_tests() 3165abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick skip_lines = map(lambda test_path: "BUG_SKIPPED SKIP : %s = FAIL" % 3175abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick test_path, tests_to_skip) 3185abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return "\n".join(skip_lines) 3195abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick 3205abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick def skipped_layout_tests(self): 321dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # Use a set to allow duplicates 322dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block tests_to_skip = set(self._expectations_from_skipped_files()) 323dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block tests_to_skip.update(self._tests_for_other_platforms()) 324dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block tests_to_skip.update(self._tests_for_disabled_features()) 3255abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return tests_to_skip 326dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 327dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _build_path(self, *comps): 3286b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner return self._filesystem.join(self._config.build_directory( 3296b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner self.get_option('configuration')), *comps) 330dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 331dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _path_to_driver(self): 332dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return self._build_path('DumpRenderTree') 333dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 3345abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick def _path_to_webcore_library(self): 3355abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return None 3365abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick 337dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _path_to_helper(self): 338dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return None 339dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 340dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _path_to_image_diff(self): 341dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return self._build_path('ImageDiff') 342dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 343dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _path_to_wdiff(self): 344dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # FIXME: This does not exist on a default Mac OS X Leopard install. 345dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return 'wdiff' 346dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 347dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def _path_to_apache(self): 348dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if not self._cached_apache_path: 349dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # The Apache binary path can vary depending on OS and distribution 350dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # See http://wiki.apache.org/httpd/DistrosDefaultLayout 351dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block for path in ["/usr/sbin/httpd", "/usr/sbin/apache2"]: 352ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if self._filesystem.exists(path): 353dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block self._cached_apache_path = path 354dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block break 355dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 356dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if not self._cached_apache_path: 357dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block _log.error("Could not find apache. Not installed or unknown path.") 358dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 359dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return self._cached_apache_path 360dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 361dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 362dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockclass WebKitDriver(base.Driver): 363dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block """WebKit implementation of the DumpRenderTree interface.""" 364dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 3654576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang def __init__(self, port, worker_number): 3664576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang self._worker_number = worker_number 367dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block self._port = port 368ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch self._driver_tempdir = port._filesystem.mkdtemp(prefix='DumpRenderTree-') 3695abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick 3705abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick def __del__(self): 371ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch self._port._filesystem.rmtree(str(self._driver_tempdir)) 372dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 3734576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang def cmd_line(self): 3744576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang cmd = self._command_wrapper(self._port.get_option('wrapper')) 3752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch cmd.append(self._port._path_to_driver()) 3764576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang if self._port.get_option('pixel_tests'): 3774576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang cmd.append('--pixel-tests') 3782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch cmd.extend(self._port.get_option('additional_drt_flag', [])) 3792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch cmd.append('-') 3804576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang return cmd 38168513a70bcd92384395513322f1b801e7bf9c729Steve Block 38221939df44de1705786c545cd1bf519d47250322dBen Murdoch def start(self): 383e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke environment = self._port.setup_environ_for_server() 384dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block environment['DYLD_FRAMEWORK_PATH'] = self._port._build_path() 385ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch environment['DUMPRENDERTREE_TEMP'] = str(self._driver_tempdir) 386dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block self._server_process = server_process.ServerProcess(self._port, 3874576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang "DumpRenderTree", self.cmd_line(), environment) 388dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 389dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def poll(self): 390dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return self._server_process.poll() 391dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 392dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def restart(self): 393dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block self._server_process.stop() 394dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block self._server_process.start() 395dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return 396dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 397dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # FIXME: This function is huge. 3982fc2651226baac27029e38c9d6ef883fa32084dbSteve Block def run_test(self, driver_input): 3992fc2651226baac27029e38c9d6ef883fa32084dbSteve Block uri = self._port.filename_to_uri(driver_input.filename) 400dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if uri.startswith("file:///"): 401dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block command = uri[7:] 402dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block else: 403dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block command = uri 404dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 4052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if driver_input.image_hash: 4062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block command += "'" + driver_input.image_hash 407dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block command += "\n" 408dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 4096b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner start_time = time.time() 410dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block self._server_process.write(command) 411dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 4122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch text = None 4132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch image = None 414dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block actual_image_hash = None 4152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch audio = None 4162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch deadline = time.time() + int(driver_input.timeout) / 1000.0 417dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 4182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch # First block is either text or audio 4192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch block = self._read_block(deadline) 4202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if block.content_type == 'audio/wav': 4212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch audio = block.decoded_content 4222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch else: 4232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch text = block.decoded_content 424dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 4252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch # Now read an optional second block of image data 4262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch block = self._read_block(deadline) 4272daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if block.content and block.content_type == 'image/png': 4282daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch image = block.decoded_content 4292daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch actual_image_hash = block.content_hash 430dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 43121939df44de1705786c545cd1bf519d47250322dBen Murdoch error_lines = self._server_process.error.splitlines() 43221939df44de1705786c545cd1bf519d47250322dBen Murdoch # FIXME: This is a hack. It is unclear why sometimes 43321939df44de1705786c545cd1bf519d47250322dBen Murdoch # we do not get any error lines from the server_process 43421939df44de1705786c545cd1bf519d47250322dBen Murdoch # probably we are not flushing stderr. 43521939df44de1705786c545cd1bf519d47250322dBen Murdoch if error_lines and error_lines[-1] == "#EOF": 43621939df44de1705786c545cd1bf519d47250322dBen Murdoch error_lines.pop() # Remove the expected "#EOF" 43721939df44de1705786c545cd1bf519d47250322dBen Murdoch error = "\n".join(error_lines) 43821939df44de1705786c545cd1bf519d47250322dBen Murdoch # FIXME: This seems like the wrong section of code to be doing 43921939df44de1705786c545cd1bf519d47250322dBen Murdoch # this reset in. 44021939df44de1705786c545cd1bf519d47250322dBen Murdoch self._server_process.error = "" 4412daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return base.DriverOutput(text, image, actual_image_hash, audio, 4422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch crash=self._server_process.crashed, test_time=time.time() - start_time, 4432daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch timeout=self._server_process.timed_out, error=error) 4442daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 4452daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch def _read_block(self, deadline): 4462daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch LENGTH_HEADER = 'Content-Length: ' 4472daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch HASH_HEADER = 'ActualHash: ' 4482daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch TYPE_HEADER = 'Content-Type: ' 4492daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch ENCODING_HEADER = 'Content-Transfer-Encoding: ' 4502daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch content_type = None 4512daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch encoding = None 4522daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch content_hash = None 4532daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch content_length = None 4542daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 4552daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch # Content is treated as binary data even though the text output 4562daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch # is usually UTF-8. 4572daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch content = '' 4582daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch timeout = deadline - time.time() 4592daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch line = self._server_process.read_line(timeout) 4602daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch while (not self._server_process.timed_out 4612daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch and not self._server_process.crashed 4622daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch and line.rstrip() != "#EOF"): 4632daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if line.startswith(TYPE_HEADER) and content_type is None: 4642daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch content_type = line.split()[1] 4652daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch elif line.startswith(ENCODING_HEADER) and encoding is None: 4662daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch encoding = line.split()[1] 4672daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch elif line.startswith(LENGTH_HEADER) and content_length is None: 4682daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch timeout = deadline - time.time() 4692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch content_length = int(line[len(LENGTH_HEADER):]) 4702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch # FIXME: Technically there should probably be another blank 4712daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch # line here, but DRT doesn't write one. 4722daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch content = self._server_process.read(timeout, content_length) 4732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch elif line.startswith(HASH_HEADER): 4742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch content_hash = line.split()[1] 4752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch else: 4762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch content += line 4772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch line = self._server_process.read_line(timeout) 4782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch timeout = deadline - time.time() 4792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return ContentBlock(content_type, encoding, content_hash, content) 480dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 481dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def stop(self): 482dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if self._server_process: 483dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block self._server_process.stop() 484dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block self._server_process = None 4852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 4862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 4872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochclass ContentBlock(object): 4882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch def __init__(self, content_type, encoding, content_hash, content): 4892daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch self.content_type = content_type 4902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch self.encoding = encoding 4912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch self.content_hash = content_hash 4922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch self.content = content 4932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if self.encoding == 'base64': 4942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch self.decoded_content = base64.b64decode(content) 4952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch else: 4962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch self.decoded_content = content 497