18a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#!/usr/bin/env python
28a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# Copyright (C) 2010 Google Inc. All rights reserved.
38a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#
48a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# Redistribution and use in source and binary forms, with or without
58a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# modification, are permitted provided that the following conditions are
68a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# met:
78a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#
88a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#     * Redistributions of source code must retain the above copyright
98a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# notice, this list of conditions and the following disclaimer.
108a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#     * Redistributions in binary form must reproduce the above
118a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# copyright notice, this list of conditions and the following disclaimer
128a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# in the documentation and/or other materials provided with the
138a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# distribution.
148a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#     * Neither the Google name nor the names of its
158a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# contributors may be used to endorse or promote products derived from
168a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# this software without specific prior written permission.
178a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#
188a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
198a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
208a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
218a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
228a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
238a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
248a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
258a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
268a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
278a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
288a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
298a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
308a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block"""Abstract base class of Port-specific entrypoints for the layout tests
318a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blocktest infrastructure (the Port and Driver classes)."""
328a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
332bde8e466a4451c7319e3a072d118917957d6554Steve Blockfrom __future__ import with_statement
342bde8e466a4451c7319e3a072d118917957d6554Steve Block
358a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockimport cgi
368a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockimport difflib
378a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockimport errno
388a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockimport os
3921939df44de1705786c545cd1bf519d47250322dBen Murdochimport shlex
408a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockimport sys
41dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport time
428a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
4381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch# Handle Python < 2.6 where multiprocessing isn't available.
4481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochtry:
4581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    import multiprocessing
4681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochexcept ImportError:
4781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    multiprocessing = None
4881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
496b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brennerfrom webkitpy.common import system
506b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brennerfrom webkitpy.common.system import filesystem
51dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockfrom webkitpy.common.system import logutils
526b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brennerfrom webkitpy.common.system import path
53dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockfrom webkitpy.common.system.executive import Executive, ScriptError
54bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenfrom webkitpy.common.system.user import User
552bde8e466a4451c7319e3a072d118917957d6554Steve Blockfrom webkitpy.layout_tests import read_checksum_from_png
562bde8e466a4451c7319e3a072d118917957d6554Steve Blockfrom webkitpy.layout_tests.port import apache_http_server
572bde8e466a4451c7319e3a072d118917957d6554Steve Blockfrom webkitpy.layout_tests.port import config as port_config
582bde8e466a4451c7319e3a072d118917957d6554Steve Blockfrom webkitpy.layout_tests.port import http_lock
592bde8e466a4451c7319e3a072d118917957d6554Steve Blockfrom webkitpy.layout_tests.port import http_server
602bde8e466a4451c7319e3a072d118917957d6554Steve Blockfrom webkitpy.layout_tests.port import test_files
612bde8e466a4451c7319e3a072d118917957d6554Steve Blockfrom webkitpy.layout_tests.port import websocket_server
62dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
63dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block_log = logutils.get_logger(__file__)
64dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
65dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
66a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochclass DummyOptions(object):
67a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    """Fake implementation of optparse.Values. Cloned from
68a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    webkitpy.tool.mocktool.MockOptions.
69a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
70a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    """
71a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
72a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    def __init__(self, **kwargs):
73a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # The caller can set option values using keyword arguments. We don't
74a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # set any values by default because we don't know how this
75a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # object will be used. Generally speaking unit tests should
76a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # subclass this or provider wrapper functions that set a common
77a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # set of options.
78a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        for key, value in kwargs.items():
79a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            self.__dict__[key] = value
80a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
818a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
828a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block# FIXME: This class should merge with webkitpy.webkit_port at some point.
838a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockclass Port(object):
846b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    """Abstract class for Port-specific hooks for the layout_test package."""
856b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
866b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    def __init__(self, port_name=None, options=None,
876b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                 executive=None,
886b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                 user=None,
896b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                 filesystem=None,
906b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                 config=None,
916b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                 **kwargs):
926b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        self._name = port_name
932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        # These are default values that should be overridden in a subclasses.
952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        # FIXME: These should really be passed in.
962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        self._operating_system = 'mac'
972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        self._version = ''
9881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        self._architecture = 'x86'
992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        self._graphics_type = 'cpu'
1002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        # FIXME: Ideally we'd have a package-wide way to get a
1022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        # well-formed options object that had all of the necessary
1032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        # options defined on it.
1042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        self._options = options or DummyOptions()
1052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1066b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        self._executive = executive or Executive()
1076b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        self._user = user or User()
1086b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        self._filesystem = filesystem or system.filesystem.FileSystem()
1092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        self._config = config or port_config.Config(self._executive, self._filesystem)
1102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1118a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        self._helper = None
1128a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        self._http_server = None
1138a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        self._webkit_base_dir = None
1148a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        self._websocket_server = None
115a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        self._http_lock = None
116a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
117a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # Python's Popen has a bug that causes any pipes opened to a
118a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # process that can't be executed to be leaked.  Since this
119a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # code is specifically designed to tolerate exec failures
120a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # to gracefully handle cases where wdiff is not installed,
121a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # the bug results in a massive file descriptor leak. As a
122a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # workaround, if an exec failure is ever experienced for
123a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # wdiff, assume it's not available.  This will leak one
124a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # file descriptor but that's better than leaking each time
125a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # wdiff would be run.
126a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        #
127a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # http://mail.python.org/pipermail/python-list/
128a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        #    2008-August/505753.html
129a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # http://bugs.python.org/issue3210
130a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        self._wdiff_available = True
131a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
1322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        # FIXME: prettypatch.py knows this path, why is it copied here?
133f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        self._pretty_patch_path = self.path_from_webkit_base("Websites",
134f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            "bugs.webkit.org", "PrettyPatch", "prettify.rb")
1352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        self._pretty_patch_available = None
1362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1372fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if not hasattr(self._options, 'configuration') or self._options.configuration is None:
138a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            self._options.configuration = self.default_configuration()
1392fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self._test_configuration = None
14081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        self._multiprocessing_is_available = (multiprocessing is not None)
1412daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        self._results_directory = None
1422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1432daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def wdiff_available(self):
1442daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return bool(self._wdiff_available)
1452daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1462daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def pretty_patch_available(self):
1472daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return bool(self._pretty_patch_available)
148dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
149dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def default_child_processes(self):
150dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """Return the number of DumpRenderTree instances to use for this
151dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        port."""
152dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return self._executive.cpu_count()
1538a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1542fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def default_worker_model(self):
1552bde8e466a4451c7319e3a072d118917957d6554Steve Block        if self._multiprocessing_is_available:
1562bde8e466a4451c7319e3a072d118917957d6554Steve Block            return 'processes'
1572bde8e466a4451c7319e3a072d118917957d6554Steve Block        return 'threads'
1582fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1598a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def baseline_path(self):
1608a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Return the absolute path to the directory to store new baselines
1618a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        in for this port."""
1628a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Port.baseline_path')
1638a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1648a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def baseline_search_path(self):
1658a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Return a list of absolute paths to directories to search under for
1668a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        baselines. The directories are searched in order."""
1678a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Port.baseline_search_path')
1688a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
169dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def check_build(self, needs_http):
170dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """This routine is used to ensure that the build is up to date
171dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        and all the needed binaries are present."""
172dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        raise NotImplementedError('Port.check_build')
173dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
174dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def check_sys_deps(self, needs_http):
1758a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """If the port needs to do some runtime checks to ensure that the
176dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        tests can be run successfully, it should override this routine.
177dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        This step can be skipped with --nocheck-sys-deps.
1788a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1798a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        Returns whether the system is properly configured."""
180dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return True
181dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
182dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def check_image_diff(self, override_step=None, logging=True):
183dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """This routine is used to check whether image_diff binary exists."""
1845abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        raise NotImplementedError('Port.check_image_diff')
1858a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
1862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def check_pretty_patch(self, logging=True):
187a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        """Checks whether we can use the PrettyPatch ruby script."""
188a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # check if Ruby is installed
189a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        try:
190a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            result = self._executive.run_command(['ruby', '--version'])
191a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        except OSError, e:
192a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if e.errno in [errno.ENOENT, errno.EACCES, errno.ECHILD]:
1932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                if logging:
1942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                    _log.error("Ruby is not installed; can't generate pretty patches.")
1952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                    _log.error('')
196a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                return False
197a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
198a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if not self.path_exists(self._pretty_patch_path):
1992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            if logging:
2002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                _log.error("Unable to find %s; can't generate pretty patches." % self._pretty_patch_path)
2012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                _log.error('')
202a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            return False
203a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
204a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return True
205a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
206dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def compare_text(self, expected_text, actual_text):
2078a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Return whether or not the two strings are *not* equal. This
2088a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        routine is used to diff text output.
2098a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
2108a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        While this is a generic routine, we include it in the Port
2118a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        interface so that it can be overriden for testing purposes."""
212dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return expected_text != actual_text
2138a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
2142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def compare_audio(self, expected_audio, actual_audio):
2152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        """Return whether the two audio files are *not* equal."""
2162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return expected_audio != actual_audio
2172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
218bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    def diff_image(self, expected_contents, actual_contents,
219e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke                   diff_filename=None, tolerance=0):
220bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        """Compare two images and produce a delta image file.
2218a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
222bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        Return True if the two images are different, False if they are the same.
2238a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        Also produce a delta image of the two images and write that into
224692e5dbf12901edacf14812a6fae25462920af42Steve Block        |diff_filename| if it is not None.
2258a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
226e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke        |tolerance| should be a percentage value (0.0 - 100.0).
227e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke        If it is omitted, the port default tolerance value is used.
228e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke
2295abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        """
2305abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        raise NotImplementedError('Port.diff_image')
231dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
2328a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
233dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def diff_text(self, expected_text, actual_text,
234dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                  expected_filename, actual_filename):
2358a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns a string containing the diff of the two text strings
2368a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        in 'unified diff' format.
2378a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
2388a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        While this is a generic routine, we include it in the Port
2398a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        interface so that it can be overriden for testing purposes."""
24068513a70bcd92384395513322f1b801e7bf9c729Steve Block
24168513a70bcd92384395513322f1b801e7bf9c729Steve Block        # The filenames show up in the diff output, make sure they're
24268513a70bcd92384395513322f1b801e7bf9c729Steve Block        # raw bytes and not unicode, so that they don't trigger join()
24368513a70bcd92384395513322f1b801e7bf9c729Steve Block        # trying to decode the input.
24468513a70bcd92384395513322f1b801e7bf9c729Steve Block        def to_raw_bytes(str):
24568513a70bcd92384395513322f1b801e7bf9c729Steve Block            if isinstance(str, unicode):
24668513a70bcd92384395513322f1b801e7bf9c729Steve Block                return str.encode('utf-8')
24768513a70bcd92384395513322f1b801e7bf9c729Steve Block            return str
24868513a70bcd92384395513322f1b801e7bf9c729Steve Block        expected_filename = to_raw_bytes(expected_filename)
24968513a70bcd92384395513322f1b801e7bf9c729Steve Block        actual_filename = to_raw_bytes(actual_filename)
2508a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        diff = difflib.unified_diff(expected_text.splitlines(True),
2518a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                                    actual_text.splitlines(True),
2528a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                                    expected_filename,
2538a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                                    actual_filename)
2548a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        return ''.join(diff)
2558a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
256dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def driver_name(self):
257dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """Returns the name of the actual binary that is performing the test,
258dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        so that it can be referred to in log messages. In most cases this
259dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        will be DumpRenderTree, but if a port uses a binary with a different
260dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        name, it can be overridden here."""
261dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return "DumpRenderTree"
262dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
2638a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def expected_baselines(self, filename, suffix, all_baselines=False):
2648a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Given a test name, finds where the baseline results are located.
2658a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
2668a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        Args:
2678a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        filename: absolute filename to test file
2688a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        suffix: file suffix of the expected results, including dot; e.g.
2698a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            '.txt' or '.png'.  This should not be None, but may be an empty
2708a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            string.
2718a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        all_baselines: If True, return an ordered list of all baseline paths
2728a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            for the given platform. If False, return only the first one.
2738a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        Returns
2748a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        a list of ( platform_dir, results_filename ), where
2758a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            platform_dir - abs path to the top of the results tree (or test
2768a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                tree)
2778a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            results_filename - relative path from top of tree to the results
2788a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                file
279ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch            (port.join() of the two gives you the full path to the file,
2808a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                unless None was returned.)
2818a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        Return values will be in the format appropriate for the current
2828a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        platform (e.g., "\\" for path separators on Windows). If the results
2838a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        file is not found, then None will be returned for the directory,
2848a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        but the expected relative pathname will still be returned.
2858a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
2868a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        This routine is generic but lives here since it is used in
2878a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        conjunction with the other baseline and filename routines that are
2888a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        platform specific.
2898a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """
290ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        testname = self._filesystem.splitext(self.relative_test_filename(filename))[0]
2918a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
2928a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        baseline_filename = testname + '-expected' + suffix
2938a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
2942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        baseline_search_path = self.get_option('additional_platform_directory', []) + self.baseline_search_path()
2958a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
2968a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        baselines = []
2978a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        for platform_dir in baseline_search_path:
2986b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            if self.path_exists(self._filesystem.join(platform_dir,
2996b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                                      baseline_filename)):
3008a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                baselines.append((platform_dir, baseline_filename))
3018a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
3028a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            if not all_baselines and baselines:
3038a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                return baselines
3048a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
3058a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        # If it wasn't found in a platform directory, return the expected
3068a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        # result in the test directory, even if no such file actually exists.
3078a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        platform_dir = self.layout_tests_dir()
3086b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        if self.path_exists(self._filesystem.join(platform_dir,
3096b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                                  baseline_filename)):
3108a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            baselines.append((platform_dir, baseline_filename))
3118a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
3128a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        if baselines:
3138a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            return baselines
3148a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
3158a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        return [(None, baseline_filename)]
3168a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
3178a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def expected_filename(self, filename, suffix):
3188a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Given a test name, returns an absolute path to its expected results.
3198a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
3208a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        If no expected results are found in any of the searched directories,
3218a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        the directory in which the test itself is located will be returned.
3228a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        The return value is in the format appropriate for the platform
3238a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        (e.g., "\\" for path separators on windows).
3248a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
3258a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        Args:
3268a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        filename: absolute filename to test file
3278a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        suffix: file suffix of the expected results, including dot; e.g. '.txt'
3288a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            or '.png'.  This should not be None, but may be an empty string.
3298a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        platform: the most-specific directory name to use to build the
3308a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            search list of directories, e.g., 'chromium-win', or
3318a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            'chromium-mac-leopard' (we follow the WebKit format)
3328a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
3338a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        This routine is generic but is implemented here to live alongside
3348a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        the other baseline and filename manipulation routines.
3358a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """
3368a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        platform_dir, baseline_filename = self.expected_baselines(
3378a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            filename, suffix)[0]
3388a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        if platform_dir:
3396b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            return self._filesystem.join(platform_dir, baseline_filename)
3406b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return self._filesystem.join(self.layout_tests_dir(), baseline_filename)
341bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
342bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    def expected_checksum(self, test):
343bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        """Returns the checksum of the image we expect the test to produce, or None if it is a text-only test."""
3442bde8e466a4451c7319e3a072d118917957d6554Steve Block        png_path = self.expected_filename(test, '.png')
3452bde8e466a4451c7319e3a072d118917957d6554Steve Block        checksum_path = self._filesystem.splitext(png_path)[0] + '.checksum'
3462bde8e466a4451c7319e3a072d118917957d6554Steve Block
3472bde8e466a4451c7319e3a072d118917957d6554Steve Block        if self.path_exists(checksum_path):
3482bde8e466a4451c7319e3a072d118917957d6554Steve Block            return self._filesystem.read_binary_file(checksum_path)
3492bde8e466a4451c7319e3a072d118917957d6554Steve Block
3502bde8e466a4451c7319e3a072d118917957d6554Steve Block        if self.path_exists(png_path):
3512bde8e466a4451c7319e3a072d118917957d6554Steve Block            with self._filesystem.open_binary_file_for_reading(png_path) as filehandle:
3522bde8e466a4451c7319e3a072d118917957d6554Steve Block                return read_checksum_from_png.read_checksum(filehandle)
3532bde8e466a4451c7319e3a072d118917957d6554Steve Block
3542bde8e466a4451c7319e3a072d118917957d6554Steve Block        return None
355bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
356bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    def expected_image(self, test):
357bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        """Returns the image we expect the test to produce."""
3586b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        path = self.expected_filename(test, '.png')
3596b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        if not self.path_exists(path):
3606b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            return None
3616b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return self._filesystem.read_binary_file(path)
362bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
3632daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def expected_audio(self, test):
3642daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        path = self.expected_filename(test, '.wav')
3652daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if not self.path_exists(path):
3662daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            return None
3672daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return self._filesystem.read_binary_file(path)
3682daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
369bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    def expected_text(self, test):
3702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        """Returns the text output we expect the test to produce, or None
3712daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if we don't expect there to be any text output.
372f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        End-of-line characters are normalized to '\n'."""
3736b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # FIXME: DRT output is actually utf-8, but since we don't decode the
3746b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # output from DRT (instead treating it as a binary string), we read the
3756b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # baselines as a binary string, too.
3766b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        path = self.expected_filename(test, '.txt')
3776b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        if not self.path_exists(path):
3782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            return None
3796b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        text = self._filesystem.read_binary_file(path)
380f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        return text.replace("\r\n", "\n")
381bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
3822bde8e466a4451c7319e3a072d118917957d6554Steve Block    def reftest_expected_filename(self, filename):
3832bde8e466a4451c7319e3a072d118917957d6554Steve Block        """Return the filename of reference we expect the test matches."""
3842bde8e466a4451c7319e3a072d118917957d6554Steve Block        return self.expected_filename(filename, '.html')
3852bde8e466a4451c7319e3a072d118917957d6554Steve Block
3862bde8e466a4451c7319e3a072d118917957d6554Steve Block    def reftest_expected_mismatch_filename(self, filename):
3872bde8e466a4451c7319e3a072d118917957d6554Steve Block        """Return the filename of reference we don't expect the test matches."""
3882bde8e466a4451c7319e3a072d118917957d6554Steve Block        return self.expected_filename(filename, '-mismatch.html')
3892bde8e466a4451c7319e3a072d118917957d6554Steve Block
3908a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def filename_to_uri(self, filename):
391a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        """Convert a test file (which is an absolute path) to a URI."""
3928a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        LAYOUTTEST_HTTP_DIR = "http/tests/"
393a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        LAYOUTTEST_WEBSOCKET_DIR = "http/tests/websocket/tests/"
3948a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
3958a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        relative_path = self.relative_test_filename(filename)
3968a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        port = None
3978a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        use_ssl = False
3988a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
399a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (relative_path.startswith(LAYOUTTEST_WEBSOCKET_DIR)
400a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            or relative_path.startswith(LAYOUTTEST_HTTP_DIR)):
4018a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            relative_path = relative_path[len(LAYOUTTEST_HTTP_DIR):]
4028a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            port = 8000
4038a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
4048a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        # Make http/tests/local run as local files. This is to mimic the
4058a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        # logic in run-webkit-tests.
4068a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        #
40781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        # TODO(dpranke): remove the SSL reference?
40881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (port and not relative_path.startswith("local/")):
4098a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            if relative_path.startswith("ssl/"):
4108a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                port += 443
4118a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                protocol = "https"
4128a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            else:
4138a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block                protocol = "http"
4148a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            return "%s://127.0.0.1:%u/%s" % (protocol, port, relative_path)
4158a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
416ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        return path.abspath_to_uri(self._filesystem.abspath(filename))
4178a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
418bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    def tests(self, paths):
419bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        """Return the list of tests found (relative to layout_tests_dir()."""
420bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        return test_files.find(self, paths)
421bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
422bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    def test_dirs(self):
423bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        """Returns the list of top-level test directories.
424bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
425bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        Used by --clobber-old-results."""
426bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        layout_tests_dir = self.layout_tests_dir()
4276b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return filter(lambda x: self._filesystem.isdir(self._filesystem.join(layout_tests_dir, x)),
4286b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                      self._filesystem.listdir(layout_tests_dir))
429bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
430bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    def path_isdir(self, path):
4316b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        """Return True if the path refers to a directory of tests."""
4326b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # Used by test_expectations.py to apply rules to whole directories.
4336b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return self._filesystem.isdir(path)
434bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
435bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    def path_exists(self, path):
4366b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        """Return True if the path refers to an existing test or baseline."""
437bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        # Used by test_expectations.py to determine if an entry refers to a
4386b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        # valid test and by printing.py to determine if baselines exist.
4396b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return self._filesystem.exists(path)
440bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
4414576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    def driver_cmd_line(self):
4424576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        """Prints the DRT command line that will be used."""
4434576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        driver = self.create_driver(0)
4444576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        return driver.cmd_line()
4454576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang
4462fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def update_baseline(self, path, data):
447bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        """Updates the baseline for a test.
448bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
449bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        Args:
450bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen            path: the actual path to use for baseline, not the path to
451bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen              the test. This function is used to update either generic or
452bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen              platform-specific baselines, but we can't infer which here.
453bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen            data: contents of the baseline.
454bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        """
4552fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self._filesystem.write_binary_file(path, data)
456bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
457bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    def uri_to_test_name(self, uri):
458bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        """Return the base layout test name for a given URI.
459bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
460bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        This returns the test name for a given URI, e.g., if you passed in
461bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        "file:///src/LayoutTests/fast/html/keygen.html" it would return
462bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        "fast/html/keygen.html".
463bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
464bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        """
465bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        test = uri
466bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        if uri.startswith("file:///"):
4676b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            prefix = path.abspath_to_uri(self.layout_tests_dir()) + "/"
468a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            return test[len(prefix):]
469bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
470bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        if uri.startswith("http://127.0.0.1:8880/"):
471bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen            # websocket tests
472bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen            return test.replace('http://127.0.0.1:8880/', '')
473bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
474bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        if uri.startswith("http://"):
475bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen            # regular HTTP test
476bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen            return test.replace('http://127.0.0.1:8000/', 'http/tests/')
477bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
478bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        if uri.startswith("https://"):
479bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen            return test.replace('https://127.0.0.1:8443/', 'http/tests/')
480bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
481bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        raise NotImplementedError('unknown url type: %s' % uri)
482bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
4838a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def layout_tests_dir(self):
4848a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Return the absolute path to the top of the LayoutTests directory."""
4858a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        return self.path_from_webkit_base('LayoutTests')
4868a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
4875abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    def skips_layout_test(self, test_name):
4885abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        """Figures out if the givent test is being skipped or not.
4895abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
4905abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        Test categories are handled as well."""
4915abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        for test_or_category in self.skipped_layout_tests():
4925abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick            if test_or_category == test_name:
4935abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick                return True
4946b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            category = self._filesystem.join(self.layout_tests_dir(),
4956b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                             test_or_category)
4966b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            if (self._filesystem.isdir(category) and
4976b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                test_name.startswith(test_or_category)):
4985abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick                return True
4995abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        return False
5005abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
5018a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def maybe_make_directory(self, *path):
5028a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Creates the specified directory if it doesn't already exist."""
5036b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        self._filesystem.maybe_make_directory(*path)
5048a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
5058a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def name(self):
5062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        """Return the name of the port (e.g., 'mac', 'chromium-win-xp')."""
5078a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        return self._name
5088a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
5092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def operating_system(self):
5102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return self._operating_system
5112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
5122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def version(self):
5132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        """Returns a string indicating the version of a given platform, e.g.
5142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        'leopard' or 'xp'.
5152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
5162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        This is used to help identify the exact port when parsing test
5172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        expectations, determining search paths, and logging information."""
5182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return self._version
5192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
5202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def graphics_type(self):
5212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        """Returns whether the port uses accelerated graphics ('gpu') or not
5222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        ('cpu')."""
5232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return self._graphics_type
5242daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
5252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def architecture(self):
5262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return self._architecture
5272fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
5282fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def real_name(self):
5292fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        """Returns the actual name of the port, not the delegate's."""
5302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return self.name()
5312fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
532a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    def get_option(self, name, default_value=None):
533a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # FIXME: Eventually we should not have to do a test for
534a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # hasattr(), and we should be able to just do
535a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        # self.options.value. See additional FIXME in the constructor.
536a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if hasattr(self._options, name):
537a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            return getattr(self._options, name)
538a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return default_value
539a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
540a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    def set_option_default(self, name, default_value):
541a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if not hasattr(self._options, name):
542a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            return setattr(self._options, name, default_value)
543a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
5448a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def path_from_webkit_base(self, *comps):
5458a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns the full path to path made by joining the top of the
5468a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        WebKit source tree and the list of path components in |*comps|."""
5476b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return self._config.path_from_webkit_base(*comps)
5488a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
549692e5dbf12901edacf14812a6fae25462920af42Steve Block    def script_path(self, script_name):
5506b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return self._config.script_path(script_name)
551692e5dbf12901edacf14812a6fae25462920af42Steve Block
5522bde8e466a4451c7319e3a072d118917957d6554Steve Block    def script_shell_command(self, script_name):
5532bde8e466a4451c7319e3a072d118917957d6554Steve Block        return self._config.script_shell_command(script_name)
5542bde8e466a4451c7319e3a072d118917957d6554Steve Block
555692e5dbf12901edacf14812a6fae25462920af42Steve Block    def path_to_test_expectations_file(self):
556692e5dbf12901edacf14812a6fae25462920af42Steve Block        """Update the test expectations to the passed-in string.
557692e5dbf12901edacf14812a6fae25462920af42Steve Block
558692e5dbf12901edacf14812a6fae25462920af42Steve Block        This is used by the rebaselining tool. Raises NotImplementedError
559692e5dbf12901edacf14812a6fae25462920af42Steve Block        if the port does not use expectations files."""
560692e5dbf12901edacf14812a6fae25462920af42Steve Block        raise NotImplementedError('Port.path_to_test_expectations_file')
561dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
5628a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def relative_test_filename(self, filename):
5638a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Relative unix-style path for a filename under the LayoutTests
5648a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        directory. Filenames outside the LayoutTests directory should raise
5658a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        an error."""
5662fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        # FIXME: On Windows, does this return test_names with forward slashes,
5672fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        # or windows-style relative paths?
568f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        assert filename.startswith(self.layout_tests_dir()), "%s did not start with %s" % (filename, self.layout_tests_dir())
5698a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        return filename[len(self.layout_tests_dir()) + 1:]
5708a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
5712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def abspath_for_test(self, test_name):
5722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        """Returns the full path to the file for a given test name. This is the
5732fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        inverse of relative_test_filename()."""
5742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return self._filesystem.normpath(self._filesystem.join(self.layout_tests_dir(), test_name))
5752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
5768a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def results_directory(self):
5772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        """Absolute path to the place to store the test results (uses --results-directory)."""
5782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if not self._results_directory:
5792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            option_val = self.get_option('results_directory') or self.default_results_directory()
5802daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            self._results_directory = self._filesystem.abspath(option_val)
5812daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return self._results_directory
5822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
5832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def default_results_directory(self):
5842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        """Absolute path to the default place to store the test results."""
5852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        raise NotImplementedError()
5868a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
5878a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def setup_test_run(self):
5886c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        """Perform port-specific work at the beginning of a test run."""
5898a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        pass
5908a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
5916c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    def setup_environ_for_server(self):
5926c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        """Perform port-specific work at the beginning of a server launch.
5936c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
5946c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        Returns:
5956c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen           Operating-system's environment.
5966c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        """
597e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block        return os.environ.copy()
5986c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
599bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen    def show_results_html_file(self, results_filename):
6008a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """This routine should display the HTML file pointed at by
6018a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        results_filename in a users' browser."""
602bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        return self._user.open_url(results_filename)
6038a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
6044576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    def create_driver(self, worker_number):
60521939df44de1705786c545cd1bf519d47250322dBen Murdoch        """Return a newly created base.Driver subclass for starting/stopping
60621939df44de1705786c545cd1bf519d47250322dBen Murdoch        the test driver."""
60721939df44de1705786c545cd1bf519d47250322dBen Murdoch        raise NotImplementedError('Port.create_driver')
6088a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
6098a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def start_helper(self):
610dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """If a port needs to reconfigure graphics settings or do other
611dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        things to ensure a known test configuration, it should override this
612dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        method."""
613dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        pass
6148a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
6158a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def start_http_server(self):
6168a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Start a web server if it is available. Do nothing if
6178a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        it isn't. This routine is allowed to (and may) fail if a server
6188a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        is already running."""
619a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if self.get_option('use_apache'):
6208a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            self._http_server = apache_http_server.LayoutTestApacheHttpd(self,
6212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                self.results_directory())
6228a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        else:
6232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            self._http_server = http_server.Lighttpd(self, self.results_directory())
6248a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        self._http_server.start()
6258a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
6268a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def start_websocket_server(self):
6278a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Start a websocket server if it is available. Do nothing if
6288a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        it isn't. This routine is allowed to (and may) fail if a server
6298a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        is already running."""
6302daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        self._websocket_server = websocket_server.PyWebSocket(self, self.results_directory())
6318a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        self._websocket_server.start()
6328a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
633a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    def acquire_http_lock(self):
634a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        self._http_lock = http_lock.HttpLock(None)
635a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        self._http_lock.wait_for_httpd_lock()
636a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
6378a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def stop_helper(self):
6388a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Shut down the test helper if it is running. Do nothing if
639dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        it isn't, or it isn't available. If a port overrides start_helper()
640dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        it must override this routine as well."""
641dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        pass
6428a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
6438a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def stop_http_server(self):
6448a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Shut down the http server if it is running. Do nothing if
6458a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        it isn't, or it isn't available."""
6468a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        if self._http_server:
6478a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            self._http_server.stop()
6488a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
6498a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def stop_websocket_server(self):
6508a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Shut down the websocket server if it is running. Do nothing if
6518a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        it isn't, or it isn't available."""
6528a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        if self._websocket_server:
6538a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block            self._websocket_server.stop()
6548a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
655a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    def release_http_lock(self):
656a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if self._http_lock:
657a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            self._http_lock.cleanup_http_lock()
658a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
6592fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    #
6602fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    # TEST EXPECTATION-RELATED METHODS
6612fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    #
6622fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
6632fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def test_configuration(self):
6642fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        """Returns the current TestConfiguration for the port."""
6652fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if not self._test_configuration:
6662fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            self._test_configuration = TestConfiguration(self)
6672fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return self._test_configuration
6682fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
6692fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def all_test_configurations(self):
6702fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return self.test_configuration().all_test_configurations()
6712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
6722daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def all_baseline_variants(self):
6732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        """Returns a list of platform names sufficient to cover all the baselines.
6742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
6752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        The list should be sorted so that a later platform  will reuse
6762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        an earlier platform's baselines if they are the same (e.g.,
6772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        'snowleopard' should precede 'leopard')."""
6782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        raise NotImplementedError
6792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
6808a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def test_expectations(self):
6818a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns the test expectations for this port.
6828a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
6838a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        Basically this string should contain the equivalent of a
6848a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        test_expectations file. See test_expectations.py for more details."""
6852fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return self._filesystem.read_text_file(self.path_to_test_expectations_file())
6868a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
687dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def test_expectations_overrides(self):
688dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """Returns an optional set of overrides for the test_expectations.
689dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
690dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        This is used by ports that have code in two repositories, and where
691dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        it is possible that you might need "downstream" expectations that
692dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        temporarily override the "upstream" expectations until the port can
693dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        sync up the two repos."""
694dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return None
695dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
696545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    def test_repository_paths(self):
697545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        """Returns a list of (repository_name, repository_path) tuples
698545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        of its depending code base.  By default it returns a list that only
699545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        contains a ('webkit', <webkitRepossitoryPath>) tuple.
700545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        """
701545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        return [('webkit', self.layout_tests_dir())]
702545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
703545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
70421939df44de1705786c545cd1bf519d47250322dBen Murdoch    _WDIFF_DEL = '##WDIFF_DEL##'
70521939df44de1705786c545cd1bf519d47250322dBen Murdoch    _WDIFF_ADD = '##WDIFF_ADD##'
70621939df44de1705786c545cd1bf519d47250322dBen Murdoch    _WDIFF_END = '##WDIFF_END##'
70721939df44de1705786c545cd1bf519d47250322dBen Murdoch
70821939df44de1705786c545cd1bf519d47250322dBen Murdoch    def _format_wdiff_output_as_html(self, wdiff):
70921939df44de1705786c545cd1bf519d47250322dBen Murdoch        wdiff = cgi.escape(wdiff)
71021939df44de1705786c545cd1bf519d47250322dBen Murdoch        wdiff = wdiff.replace(self._WDIFF_DEL, "<span class=del>")
71121939df44de1705786c545cd1bf519d47250322dBen Murdoch        wdiff = wdiff.replace(self._WDIFF_ADD, "<span class=add>")
71221939df44de1705786c545cd1bf519d47250322dBen Murdoch        wdiff = wdiff.replace(self._WDIFF_END, "</span>")
71321939df44de1705786c545cd1bf519d47250322dBen Murdoch        html = "<head><style>.del { background: #faa; } "
71421939df44de1705786c545cd1bf519d47250322dBen Murdoch        html += ".add { background: #afa; }</style></head>"
71521939df44de1705786c545cd1bf519d47250322dBen Murdoch        html += "<pre>%s</pre>" % wdiff
71621939df44de1705786c545cd1bf519d47250322dBen Murdoch        return html
71721939df44de1705786c545cd1bf519d47250322dBen Murdoch
71821939df44de1705786c545cd1bf519d47250322dBen Murdoch    def _wdiff_command(self, actual_filename, expected_filename):
71921939df44de1705786c545cd1bf519d47250322dBen Murdoch        executable = self._path_to_wdiff()
72021939df44de1705786c545cd1bf519d47250322dBen Murdoch        return [executable,
72121939df44de1705786c545cd1bf519d47250322dBen Murdoch                "--start-delete=%s" % self._WDIFF_DEL,
72221939df44de1705786c545cd1bf519d47250322dBen Murdoch                "--end-delete=%s" % self._WDIFF_END,
72321939df44de1705786c545cd1bf519d47250322dBen Murdoch                "--start-insert=%s" % self._WDIFF_ADD,
72421939df44de1705786c545cd1bf519d47250322dBen Murdoch                "--end-insert=%s" % self._WDIFF_END,
72521939df44de1705786c545cd1bf519d47250322dBen Murdoch                actual_filename,
72621939df44de1705786c545cd1bf519d47250322dBen Murdoch                expected_filename]
72721939df44de1705786c545cd1bf519d47250322dBen Murdoch
72821939df44de1705786c545cd1bf519d47250322dBen Murdoch    @staticmethod
72921939df44de1705786c545cd1bf519d47250322dBen Murdoch    def _handle_wdiff_error(script_error):
73021939df44de1705786c545cd1bf519d47250322dBen Murdoch        # Exit 1 means the files differed, any other exit code is an error.
73121939df44de1705786c545cd1bf519d47250322dBen Murdoch        if script_error.exit_code != 1:
73221939df44de1705786c545cd1bf519d47250322dBen Murdoch            raise script_error
73321939df44de1705786c545cd1bf519d47250322dBen Murdoch
73421939df44de1705786c545cd1bf519d47250322dBen Murdoch    def _run_wdiff(self, actual_filename, expected_filename):
73521939df44de1705786c545cd1bf519d47250322dBen Murdoch        """Runs wdiff and may throw exceptions.
73621939df44de1705786c545cd1bf519d47250322dBen Murdoch        This is mostly a hook for unit testing."""
73721939df44de1705786c545cd1bf519d47250322dBen Murdoch        # Diffs are treated as binary as they may include multiple files
73821939df44de1705786c545cd1bf519d47250322dBen Murdoch        # with conflicting encodings.  Thus we do not decode the output.
73921939df44de1705786c545cd1bf519d47250322dBen Murdoch        command = self._wdiff_command(actual_filename, expected_filename)
74021939df44de1705786c545cd1bf519d47250322dBen Murdoch        wdiff = self._executive.run_command(command, decode_output=False,
74121939df44de1705786c545cd1bf519d47250322dBen Murdoch            error_handler=self._handle_wdiff_error)
74221939df44de1705786c545cd1bf519d47250322dBen Murdoch        return self._format_wdiff_output_as_html(wdiff)
74321939df44de1705786c545cd1bf519d47250322dBen Murdoch
7448a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def wdiff_text(self, actual_filename, expected_filename):
7458a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns a string of HTML indicating the word-level diff of the
7468a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        contents of the two filenames. Returns an empty string if word-level
7478a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        diffing isn't available."""
748a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if not self._wdiff_available:
74921939df44de1705786c545cd1bf519d47250322dBen Murdoch            return ""
7508a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        try:
75121939df44de1705786c545cd1bf519d47250322dBen Murdoch            # It's possible to raise a ScriptError we pass wdiff invalid paths.
75221939df44de1705786c545cd1bf519d47250322dBen Murdoch            return self._run_wdiff(actual_filename, expected_filename)
7538a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        except OSError, e:
75421939df44de1705786c545cd1bf519d47250322dBen Murdoch            if e.errno in [errno.ENOENT, errno.EACCES, errno.ECHILD]:
75521939df44de1705786c545cd1bf519d47250322dBen Murdoch                # Silently ignore cases where wdiff is missing.
756a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                self._wdiff_available = False
75721939df44de1705786c545cd1bf519d47250322dBen Murdoch                return ""
75821939df44de1705786c545cd1bf519d47250322dBen Murdoch            raise
7598a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
760a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    # This is a class variable so we can test error output easily.
761a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    _pretty_patch_error_html = "Failed to run PrettyPatch, see error log."
762dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
763dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def pretty_patch_text(self, diff_path):
7642daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if self._pretty_patch_available is None:
7652daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            self._pretty_patch_available = self.check_pretty_patch(logging=False)
766a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if not self._pretty_patch_available:
767dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return self._pretty_patch_error_html
768ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        command = ("ruby", "-I", self._filesystem.dirname(self._pretty_patch_path),
769a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                   self._pretty_patch_path, diff_path)
770dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        try:
77121939df44de1705786c545cd1bf519d47250322dBen Murdoch            # Diffs are treated as binary (we pass decode_output=False) as they
77221939df44de1705786c545cd1bf519d47250322dBen Murdoch            # may contain multiple files of conflicting encodings.
77321939df44de1705786c545cd1bf519d47250322dBen Murdoch            return self._executive.run_command(command, decode_output=False)
774dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        except OSError, e:
775dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # If the system is missing ruby log the error and stop trying.
776a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            self._pretty_patch_available = False
777dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            _log.error("Failed to run PrettyPatch (%s): %s" % (command, e))
778dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return self._pretty_patch_error_html
779dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        except ScriptError, e:
780a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            # If ruby failed to run for some reason, log the command
781a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            # output and stop trying.
782a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            self._pretty_patch_available = False
783a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            _log.error("Failed to run PrettyPatch (%s):\n%s" % (command,
784a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                       e.message_with_output()))
785dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return self._pretty_patch_error_html
786dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
787dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def default_configuration(self):
7886b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return self._config.default_configuration()
789dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
7908a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    #
7918a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    # PROTECTED ROUTINES
7928a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    #
7938a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    # The routines below should only be called by routines in this class
7948a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    # or any of its subclasses.
7958a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    #
7966b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    def _webkit_build_directory(self, args):
7976b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return self._config.build_directory(args[0])
7988a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
7998a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def _path_to_apache(self):
8008a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns the full path to the apache binary.
8018a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8028a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        This is needed only by ports that use the apache_http_server module."""
8038a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Port.path_to_apache')
8048a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8058a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def _path_to_apache_config_file(self):
8068a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns the full path to the apache binary.
8078a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8088a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        This is needed only by ports that use the apache_http_server module."""
8098a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Port.path_to_apache_config_file')
8108a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
811dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def _path_to_driver(self, configuration=None):
8128a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns the full path to the test driver (DumpRenderTree)."""
8134576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        raise NotImplementedError('Port._path_to_driver')
8148a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8155abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    def _path_to_webcore_library(self):
8165abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        """Returns the full path to a built copy of WebCore."""
8175abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick        raise NotImplementedError('Port.path_to_webcore_library')
8185abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick
8198a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def _path_to_helper(self):
8208a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns the full path to the layout_test_helper binary, which
8218a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        is used to help configure the system for the test run, or None
8228a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        if no helper is needed.
8238a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8248a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        This is likely only used by start/stop_helper()."""
8258a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Port._path_to_helper')
8268a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8278a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def _path_to_image_diff(self):
8288a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns the full path to the image_diff binary, or None if it
8298a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        is not available.
8308a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8318a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        This is likely used only by diff_image()"""
8328a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Port.path_to_image_diff')
8338a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8348a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def _path_to_lighttpd(self):
8358a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns the path to the LigHTTPd binary.
8368a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8378a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        This is needed only by ports that use the http_server.py module."""
8388a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Port._path_to_lighttpd')
8398a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8408a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def _path_to_lighttpd_modules(self):
8418a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns the path to the LigHTTPd modules directory.
8428a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8438a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        This is needed only by ports that use the http_server.py module."""
8448a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Port._path_to_lighttpd_modules')
8458a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8468a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def _path_to_lighttpd_php(self):
8478a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns the path to the LigHTTPd PHP executable.
8488a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8498a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        This is needed only by ports that use the http_server.py module."""
8508a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Port._path_to_lighttpd_php')
8518a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8528a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def _path_to_wdiff(self):
8538a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns the full path to the wdiff binary, or None if it is
8548a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        not available.
8558a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8568a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        This is likely used only by wdiff_text()"""
8578a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Port._path_to_wdiff')
8588a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8598a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def _shut_down_http_server(self, pid):
8608a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Forcefully and synchronously kills the web server.
8618a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8628a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        This routine should only be called from http_server.py or its
8638a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        subclasses."""
8648a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Port._shut_down_http_server')
8658a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8668a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def _webkit_baseline_path(self, platform):
8678a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Return the  full path to the top of the baseline tree for a
8688a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        given platform."""
8696b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        return self._filesystem.join(self.layout_tests_dir(), 'platform',
8706b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                                     platform)
8718a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8728a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
8732fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockclass DriverInput(object):
8742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    """Holds the input parameters for a driver."""
8752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8762fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def __init__(self, filename, timeout, image_hash):
8772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        """Initializes a DriverInput object.
8782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8792fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        Args:
8802fc2651226baac27029e38c9d6ef883fa32084dbSteve Block          filename: Full path to the test.
8812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block          timeout: Timeout in msecs the driver should use while running the test
8822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block          image_hash: A image checksum which is used to avoid doing an image dump if
8832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                     the checksums match.
8842fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        """
8852fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self.filename = filename
8862fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self.timeout = timeout
8872fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self.image_hash = image_hash
8882fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8892fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8902fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockclass DriverOutput(object):
8912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    """Groups information about a output from driver for easy passing of data."""
8922fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def __init__(self, text, image, image_hash, audio,
8942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                 crash=False, test_time=0, timeout=False, error=''):
8952fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        """Initializes a TestOutput object.
8962fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8972fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        Args:
8982fc2651226baac27029e38c9d6ef883fa32084dbSteve Block          text: a text output
8992fc2651226baac27029e38c9d6ef883fa32084dbSteve Block          image: an image output
9002fc2651226baac27029e38c9d6ef883fa32084dbSteve Block          image_hash: a string containing the checksum of the image
9012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch          audio: contents of an audio stream, if any (in WAV format)
9022fc2651226baac27029e38c9d6ef883fa32084dbSteve Block          crash: a boolean indicating whether the driver crashed on the test
9032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch          test_time: the time the test took to execute
9042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block          timeout: a boolean indicating whehter the test timed out
9052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block          error: any unexpected or additional (or error) text output
9062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        """
9072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self.text = text
9082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self.image = image
9092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self.image_hash = image_hash
9102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        self.audio = audio
9112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self.crash = crash
9122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self.test_time = test_time
9132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self.timeout = timeout
9142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self.error = error
9152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9178a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockclass Driver:
9188a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    """Abstract interface for the DumpRenderTree interface."""
9198a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
9204576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    def __init__(self, port, worker_number):
9218a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Initialize a Driver to subsequently run tests.
9228a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
9238a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        Typically this routine will spawn DumpRenderTree in a config
9248a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        ready for subsequent input.
9258a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
9268a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        port - reference back to the port object.
9274576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        worker_number - identifier for a particular worker/driver instance
92868513a70bcd92384395513322f1b801e7bf9c729Steve Block        """
9298a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Driver.__init__')
9308a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
9312fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def run_test(self, driver_input):
9328a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Run a single test and return the results.
9338a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
9348a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        Note that it is okay if a test times out or crashes and leaves
9358a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        the driver in an indeterminate state. The upper layers of the program
9368a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        are responsible for cleaning up and ensuring things are okay.
9378a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
9384576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        Args:
9392fc2651226baac27029e38c9d6ef883fa32084dbSteve Block          driver_input: a DriverInput object
9408a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
9412fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        Returns a DriverOutput object.
94281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch          Note that DriverOutput.image will be '' (empty string) if a test crashes.
9436b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        """
9448a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Driver.run_test')
9458a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
94621939df44de1705786c545cd1bf519d47250322dBen Murdoch    # FIXME: This is static so we can test it w/o creating a Base instance.
94721939df44de1705786c545cd1bf519d47250322dBen Murdoch    @classmethod
94821939df44de1705786c545cd1bf519d47250322dBen Murdoch    def _command_wrapper(cls, wrapper_option):
94921939df44de1705786c545cd1bf519d47250322dBen Murdoch        # Hook for injecting valgrind or other runtime instrumentation,
95021939df44de1705786c545cd1bf519d47250322dBen Murdoch        # used by e.g. tools/valgrind/valgrind_tests.py.
95121939df44de1705786c545cd1bf519d47250322dBen Murdoch        wrapper = []
95221939df44de1705786c545cd1bf519d47250322dBen Murdoch        browser_wrapper = os.environ.get("BROWSER_WRAPPER", None)
95321939df44de1705786c545cd1bf519d47250322dBen Murdoch        if browser_wrapper:
95421939df44de1705786c545cd1bf519d47250322dBen Murdoch            # FIXME: There seems to be no reason to use BROWSER_WRAPPER over --wrapper.
95521939df44de1705786c545cd1bf519d47250322dBen Murdoch            # Remove this code any time after the date listed below.
95621939df44de1705786c545cd1bf519d47250322dBen Murdoch            _log.error("BROWSER_WRAPPER is deprecated, please use --wrapper instead.")
95721939df44de1705786c545cd1bf519d47250322dBen Murdoch            _log.error("BROWSER_WRAPPER will be removed any time after June 1st 2010 and your scripts will break.")
95821939df44de1705786c545cd1bf519d47250322dBen Murdoch            wrapper += [browser_wrapper]
95921939df44de1705786c545cd1bf519d47250322dBen Murdoch
96021939df44de1705786c545cd1bf519d47250322dBen Murdoch        if wrapper_option:
96121939df44de1705786c545cd1bf519d47250322dBen Murdoch            wrapper += shlex.split(wrapper_option)
96221939df44de1705786c545cd1bf519d47250322dBen Murdoch        return wrapper
96321939df44de1705786c545cd1bf519d47250322dBen Murdoch
9648a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def poll(self):
9658a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        """Returns None if the Driver is still running. Returns the returncode
9668a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        if it has exited."""
9678a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Driver.poll')
9688a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
9698a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    def stop(self):
9708a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        raise NotImplementedError('Driver.stop')
9712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9732fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockclass TestConfiguration(object):
9742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def __init__(self, port=None, os=None, version=None, architecture=None,
9752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                 build_type=None, graphics_type=None):
9762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        self.os = os or port.operating_system()
9772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        self.version = version or port.version()
97881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        self.architecture = architecture or port.architecture()
9792fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self.build_type = build_type or port._options.configuration.lower()
9802fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        self.graphics_type = graphics_type or port.graphics_type()
9812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def items(self):
9832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return self.__dict__.items()
9842fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9852fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def keys(self):
9862fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return self.__dict__.keys()
9872fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9882fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def __str__(self):
98981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        return ("<%(os)s, %(version)s, %(architecture)s, %(build_type)s, %(graphics_type)s>" %
9902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                self.__dict__)
9912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9922fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def __repr__(self):
9932fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return "TestConfig(os='%(os)s', version='%(version)s', architecture='%(architecture)s', build_type='%(build_type)s', graphics_type='%(graphics_type)s')" % self.__dict__
9942fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9952fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def values(self):
9962fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        """Returns the configuration values of this instance as a tuple."""
9972fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return self.__dict__.values()
9982fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9992fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def all_test_configurations(self):
10002fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        """Returns a sequence of the TestConfigurations the port supports."""
10012fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        # By default, we assume we want to test every graphics type in
10022fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        # every configuration on every system.
10032fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        test_configurations = []
10042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        for system in self.all_systems():
10052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            for build_type in self.all_build_types():
10062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                for graphics_type in self.all_graphics_types():
10072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                    test_configurations.append(TestConfiguration(
10082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                        os=system[0],
10092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                        version=system[1],
10102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                        architecture=system[2],
10112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                        build_type=build_type,
10122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                        graphics_type=graphics_type))
10132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return test_configurations
10142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
10152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def all_systems(self):
10162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return (('mac', 'leopard', 'x86'),
10172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                ('mac', 'snowleopard', 'x86'),
10182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                ('win', 'xp', 'x86'),
10192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                ('win', 'vista', 'x86'),
10202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                ('win', 'win7', 'x86'),
102181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                ('linux', 'hardy', 'x86'),
102281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                ('linux', 'hardy', 'x86_64'))
10232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
10242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def all_build_types(self):
10252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return ('debug', 'release')
10262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
10272fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    def all_graphics_types(self):
10282fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return ('cpu', 'gpu')
1029