Merge from Chromium at DEPS revision r198571
This commit was generated by merge_to_master.py.
Change-Id: I3a7f89ea6b8c017335bd52739166aed708cad1e5
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/apple.py b/Tools/Scripts/webkitpy/layout_tests/port/apple.py
deleted file mode 100644
index 9290bca..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/apple.py
+++ /dev/null
@@ -1,108 +0,0 @@
-# Copyright (C) 2011 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the Google name nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import logging
-
-from webkitpy.layout_tests.port.base import Port
-from webkitpy.layout_tests.models.test_configuration import TestConfiguration
-
-
-_log = logging.getLogger(__name__)
-
-
-class ApplePort(Port):
- """Shared logic between all of Apple's ports."""
-
- # This is used to represent the version of an operating system
- # corresponding to the "mac" or "win" base LayoutTests/platform
- # directory. I'm not sure this concept is very useful,
- # but it gives us a way to refer to fallback paths *only* including
- # the base directory.
- # This is mostly done because TestConfiguration assumes that self.version()
- # will never return None. (None would be another way to represent this concept.)
- # Apple supposedly has explicit "future" results which are kept in an internal repository.
- # It's possible that Apple would want to fix this code to work better with those results.
- FUTURE_VERSION = 'future' # FIXME: This whole 'future' thing feels like a hack.
-
- # overridden in subclasses
- VERSION_FALLBACK_ORDER = []
- ARCHITECTURES = []
-
- @classmethod
- def determine_full_port_name(cls, host, options, port_name):
- options = options or {}
- if port_name in (cls.port_name, cls.port_name + '-wk2'):
- # If the port_name matches the (badly named) cls.port_name, that
- # means that they passed 'mac' or 'win' and didn't specify a version.
- # That convention means that we're supposed to use the version currently
- # being run, so this won't work if you're not on mac or win (respectively).
- # If you're not on the o/s in question, you must specify a full version or -future (cf. above).
- assert host.platform.os_name in port_name, "%s is not in %s!" % (host.platform.os_name, port_name)
- if port_name == cls.port_name and not getattr(options, 'webkit_test_runner', False):
- port_name = cls.port_name + '-' + host.platform.os_version
- else:
- port_name = cls.port_name + '-' + host.platform.os_version + '-wk2'
- elif getattr(options, 'webkit_test_runner', False) and '-wk2' not in port_name:
- port_name += '-wk2'
-
- return port_name
-
- def _strip_port_name_prefix(self, port_name):
- # Callers treat this return value as the "version", which only works
- # because Apple ports use a simple name-version port_name scheme.
- # FIXME: This parsing wouldn't be needed if port_name handling was moved to factory.py
- # instead of the individual port constructors.
- return port_name[len(self.port_name + '-'):]
-
- def __init__(self, host, port_name, **kwargs):
- super(ApplePort, self).__init__(host, port_name, **kwargs)
-
- allowed_port_names = self.VERSION_FALLBACK_ORDER + [self.operating_system() + "-future"]
- port_name = port_name.replace('-wk2', '')
- self._version = self._strip_port_name_prefix(port_name)
- assert port_name in allowed_port_names, "%s is not in %s" % (port_name, allowed_port_names)
-
- def _skipped_file_search_paths(self):
- # We don't have a dedicated Skipped file for the most recent version of the port;
- # we just use the one in platform/{mac,win}
- most_recent_name = self.VERSION_FALLBACK_ORDER[-1]
- return set(filter(lambda name: name != most_recent_name, super(ApplePort, self)._skipped_file_search_paths()))
-
- # FIXME: A more sophisticated version of this function should move to WebKitPort and replace all calls to name().
- # This is also a misleading name, since 'mac-future' gets remapped to 'mac'.
- def _port_name_with_version(self):
- return self.name().replace('-future', '').replace('-wk2', '')
-
- def _generate_all_test_configurations(self):
- configurations = []
- allowed_port_names = self.VERSION_FALLBACK_ORDER + [self.operating_system() + "-future"]
- for port_name in allowed_port_names:
- for build_type in self.ALL_BUILD_TYPES:
- for architecture in self.ARCHITECTURES:
- configurations.append(TestConfiguration(version=self._strip_port_name_prefix(port_name), architecture=architecture, build_type=build_type))
- return configurations
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base.py b/Tools/Scripts/webkitpy/layout_tests/port/base.py
index 0811c9f..56f7662 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -54,6 +54,7 @@
from webkitpy.common.system.executive import ScriptError
from webkitpy.common.system.systemhost import SystemHost
from webkitpy.common.webkit_finder import WebKitFinder
+from webkitpy.layout_tests.layout_package.bot_test_expectations import BotTestExpectations
from webkitpy.layout_tests.models.test_configuration import TestConfiguration
from webkitpy.layout_tests.port import config as port_config
from webkitpy.layout_tests.port import driver
@@ -84,14 +85,13 @@
ALL_BUILD_TYPES = ('debug', 'release')
+ CONTENT_SHELL_NAME = 'content_shell'
+
@classmethod
def determine_full_port_name(cls, host, options, port_name):
"""Return a fully-specified port name that can be used to construct objects."""
# Subclasses will usually override this.
- options = options or {}
assert port_name.startswith(cls.port_name)
- if getattr(options, 'webkit_test_runner', False) and not '-wk2' in port_name:
- return port_name + '-wk2'
return port_name
def __init__(self, host, port_name, options=None, **kwargs):
@@ -109,9 +109,6 @@
# options defined on it.
self._options = options or optparse.Values()
- if self._name and '-wk2' in self._name:
- self._options.webkit_test_runner = True
-
self.host = host
self._executive = host.executive
self._filesystem = host.filesystem
@@ -141,7 +138,7 @@
self._wdiff_available = None
# FIXME: prettypatch.py knows this path, why is it copied here?
- self._pretty_patch_path = self.path_from_webkit_base("Websites", "bugs.webkit.org", "PrettyPatch", "prettify.rb")
+ self._pretty_patch_path = self.path_from_webkit_base("Tools", "Scripts", "webkitruby", "PrettyPatch", "prettify.rb")
self._pretty_patch_available = None
if not hasattr(options, 'configuration') or not options.configuration:
@@ -151,7 +148,12 @@
self._results_directory = None
self._root_was_set = hasattr(options, 'root') and options.root
+ def buildbot_archives_baselines(self):
+ return True
+
def additional_drt_flag(self):
+ if self.driver_name() == self.CONTENT_SHELL_NAME:
+ return ['--dump-render-tree']
return []
def supports_per_test_timeout(self):
@@ -162,10 +164,6 @@
return False
def default_timeout_ms(self):
- if self.get_option('webkit_test_runner'):
- # Add some more time to WebKitTestRunner because it needs to syncronise the state
- # with the web process and we want to detect if there is a problem with that in the driver.
- return 80 * 1000
return 35 * 1000
def driver_stop_timeout(self):
@@ -223,8 +221,6 @@
"""Return a list of absolute paths to directories to search under for
baselines. The directories are searched in order."""
search_paths = []
- if self.get_option('webkit_test_runner'):
- search_paths.append(self._wk2_port_name())
search_paths.append(self.name())
if self.name() != self.port_name:
search_paths.append(self.port_name)
@@ -242,7 +238,7 @@
"""This routine is used to ensure that the build is up to date
and all the needed binaries are present."""
# If we're using a pre-built copy of WebKit (--root), we assume it also includes a build of DRT.
- if not self._root_was_set and self.get_option('build') and not self._build_driver():
+ if not self._root_was_set and self.get_option('build'):
return False
if not self._check_driver():
return False
@@ -398,8 +394,8 @@
def driver_name(self):
if self.get_option('driver_name'):
return self.get_option('driver_name')
- if self.get_option('webkit_test_runner'):
- return 'WebKitTestRunner'
+ if self.get_option('content_shell'):
+ return self.CONTENT_SHELL_NAME
return 'DumpRenderTree'
def expected_baselines_by_extension(self, test_name):
@@ -421,7 +417,7 @@
def baseline_extensions(self):
"""Returns a tuple of all of the non-reftest baseline extensions we use. The extensions include the leading '.'."""
- return ('.wav', '.webarchive', '.txt', '.png')
+ return ('.wav', '.txt', '.png')
def expected_baselines(self, test_name, suffix, all_baselines=False):
"""Given a test name, finds where the baseline results are located.
@@ -538,9 +534,7 @@
# baselines as a binary string, too.
baseline_path = self.expected_filename(test_name, '.txt')
if not self._filesystem.exists(baseline_path):
- baseline_path = self.expected_filename(test_name, '.webarchive')
- if not self._filesystem.exists(baseline_path):
- return None
+ return None
text = self._filesystem.read_binary_file(baseline_path)
return text.replace("\r\n", "\n")
@@ -605,11 +599,11 @@
def _real_tests(self, paths):
# When collecting test cases, skip these directories
skipped_directories = set(['.svn', '_svn', 'resources', 'script-tests', 'reference', 'reftest'])
- files = find_files.find(self._filesystem, self.layout_tests_dir(), paths, skipped_directories, Port._is_test_file, self.test_key)
+ files = find_files.find(self._filesystem, self.layout_tests_dir(), paths, skipped_directories, Port.is_test_file, self.test_key)
return [self.relative_test_filename(f) for f in files]
# When collecting test cases, we include any file with these extensions.
- _supported_file_extensions = set(['.html', '.shtml', '.xml', '.xhtml', '.pl',
+ _supported_file_extensions = set(['.html', '.xml', '.xhtml', '.pl',
'.htm', '.php', '.svg', '.mht'])
@staticmethod
@@ -630,7 +624,7 @@
return extension in Port._supported_file_extensions
@staticmethod
- def _is_test_file(filesystem, dirname, filename):
+ def is_test_file(filesystem, dirname, filename):
return Port._has_supported_extension(filesystem, filename) and not Port.is_reference_html_file(filesystem, dirname, filename)
def test_key(self, test_name):
@@ -809,22 +803,6 @@
def path_to_generic_test_expectations_file(self):
return self._filesystem.join(self.layout_tests_dir(), 'TestExpectations')
- @memoized
- def path_to_test_expectations_file(self):
- """Update the test expectations to the passed-in string.
-
- This is used by the rebaselining tool. Raises NotImplementedError
- if the port does not use expectations files."""
-
- # FIXME: We need to remove this when we make rebaselining work with multiple files and just generalize expectations_files().
-
- # test_expectations are always in mac/ not mac-leopard/ by convention, hence we use port_name instead of name().
- port_name = self.port_name
- if port_name.startswith('chromium'):
- port_name = 'chromium'
-
- return self._filesystem.join(self._webkit_baseline_path(port_name), 'TestExpectations')
-
def relative_test_filename(self, filename):
"""Returns a test_name a relative unix-style path for a filename under the LayoutTests
directory. Ports may legitimately return abspaths here if no relpath makes sense."""
@@ -1043,9 +1021,8 @@
raise NotImplementedError
def uses_test_expectations_file(self):
- # This is different from checking test_expectations() is None, because
- # some ports have Skipped files which are returned as part of test_expectations().
- return self._filesystem.exists(self.path_to_test_expectations_file())
+ # FIXME: Remove this method.
+ return True
def warn_if_bug_missing_in_test_expectations(self):
return False
@@ -1061,6 +1038,12 @@
# FIXME: rename this to test_expectations() once all the callers are updated to know about the ordered dict.
expectations = OrderedDict()
+ ignore_flaky_tests = self.get_option('ignore_flaky_tests')
+ if ignore_flaky_tests == 'very-flaky' or ignore_flaky_tests == 'maybe-flaky':
+ ignore_only_very_flaky = self.get_option('ignore_flaky_tests') == 'very-flaky'
+ full_port_name = self.determine_full_port_name(self.host, self._options, self.port_name)
+ expectations['autogenerated'] = BotTestExpectations(ignore_only_very_flaky).expectations_string(full_port_name)
+
for path in self.expectations_files():
if self._filesystem.exists(path):
expectations[path] = self._filesystem.read_text_file(path)
@@ -1083,11 +1066,6 @@
if non_wk2_name != self.port_name:
search_paths.append(non_wk2_name)
- if self.get_option('webkit_test_runner'):
- # Because nearly all of the skipped tests for WebKit 2 are due to cross-platform
- # issues, all wk2 ports share a skipped list under platform/wk2.
- search_paths.extend(["wk2", self._wk2_port_name()])
-
search_paths.extend(self.get_option("additional_platform_directory", []))
return [self._filesystem.join(self._webkit_baseline_path(d), 'TestExpectations') for d in search_paths]
@@ -1204,13 +1182,7 @@
"""Returns the full path to the apache binary.
This is needed only by ports that use the apache_http_server module."""
- # The Apache binary path can vary depending on OS and distribution
- # See http://wiki.apache.org/httpd/DistrosDefaultLayout
- for path in ["/usr/sbin/httpd", "/usr/sbin/apache2"]:
- if self._filesystem.exists(path):
- return path
- _log.error("Could not find apache. Not installed or unknown path.")
- return None
+ raise NotImplementedError('Port._path_to_apache')
# FIXME: This belongs on some platform abstraction instead of Port.
def _is_redhat_based(self):
@@ -1325,7 +1297,7 @@
def _generate_all_test_configurations(self):
"""Generates a list of TestConfiguration instances, representing configurations
for a platform across all OSes, architectures, build and graphics types."""
- raise NotImplementedError('Port._generate_test_configurations')
+ raise NotImplementedError('Port._generate_all_test_configurations')
def _driver_class(self):
"""Returns the port's driver implementation."""
@@ -1431,28 +1403,6 @@
_log.debug('Output of %s:\n%s' % (run_script_command, output))
return output
- def _build_driver(self):
- environment = self.host.copy_current_environment()
- environment.disable_gcc_smartquotes()
- env = environment.to_dictionary()
-
- # FIXME: We build both DumpRenderTree and WebKitTestRunner for
- # WebKitTestRunner runs because DumpRenderTree still includes
- # the DumpRenderTreeSupport module and the TestNetscapePlugin.
- # These two projects should be factored out into their own
- # projects.
- try:
- self._run_script("build-dumprendertree", args=self._build_driver_flags(), env=env)
- if self.get_option('webkit_test_runner'):
- self._run_script("build-webkittestrunner", args=self._build_driver_flags(), env=env)
- except ScriptError, e:
- _log.error(e.message_with_output(output_limit=None))
- return False
- return True
-
- def _build_driver_flags(self):
- return []
-
def _tests_for_other_platforms(self):
# By default we will skip any directory under LayoutTests/platform
# that isn't in our baseline search path (this mirrors what
@@ -1513,7 +1463,6 @@
return {
"MathMLElement": ["mathml"],
"GraphicsLayer": ["compositing"],
- "WebCoreHas3DRendering": ["animations/3d", "transforms/3d"],
"WebGLShader": ["fast/canvas/webgl", "compositing/webgl", "http/tests/canvas/webgl", "webgl"],
"MHTMLArchive": ["mhtml"],
"CSSVariableValue": ["fast/css/variables", "inspector/styles/variables"],
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
index 7685695..393076f 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
@@ -293,14 +293,6 @@
self.assertEqual(environment['FOO'], 'BAR')
self.assertEqual(environment['BAR'], 'FOO')
- def test_uses_test_expectations_file(self):
- port = self.make_port(port_name='foo')
- port.port_name = 'foo'
- port.path_to_test_expectations_file = lambda: '/mock-results/TestExpectations'
- self.assertFalse(port.uses_test_expectations_file())
- port._filesystem = MockFileSystem({'/mock-results/TestExpectations': ''})
- self.assertTrue(port.uses_test_expectations_file())
-
def test_find_no_paths_specified(self):
port = self.make_port(with_tests=True)
layout_tests_dir = port.layout_tests_dir()
@@ -329,23 +321,22 @@
def test_is_test_file(self):
filesystem = MockFileSystem()
- self.assertTrue(Port._is_test_file(filesystem, '', 'foo.html'))
- self.assertTrue(Port._is_test_file(filesystem, '', 'foo.shtml'))
- self.assertTrue(Port._is_test_file(filesystem, '', 'foo.svg'))
- self.assertTrue(Port._is_test_file(filesystem, '', 'test-ref-test.html'))
- self.assertFalse(Port._is_test_file(filesystem, '', 'foo.png'))
- self.assertFalse(Port._is_test_file(filesystem, '', 'foo-expected.html'))
- self.assertFalse(Port._is_test_file(filesystem, '', 'foo-expected.svg'))
- self.assertFalse(Port._is_test_file(filesystem, '', 'foo-expected.xht'))
- self.assertFalse(Port._is_test_file(filesystem, '', 'foo-expected-mismatch.html'))
- self.assertFalse(Port._is_test_file(filesystem, '', 'foo-expected-mismatch.svg'))
- self.assertFalse(Port._is_test_file(filesystem, '', 'foo-expected-mismatch.xhtml'))
- self.assertFalse(Port._is_test_file(filesystem, '', 'foo-ref.html'))
- self.assertFalse(Port._is_test_file(filesystem, '', 'foo-notref.html'))
- self.assertFalse(Port._is_test_file(filesystem, '', 'foo-notref.xht'))
- self.assertFalse(Port._is_test_file(filesystem, '', 'foo-ref.xhtml'))
- self.assertFalse(Port._is_test_file(filesystem, '', 'ref-foo.html'))
- self.assertFalse(Port._is_test_file(filesystem, '', 'notref-foo.xhr'))
+ self.assertTrue(Port.is_test_file(filesystem, '', 'foo.html'))
+ self.assertTrue(Port.is_test_file(filesystem, '', 'foo.svg'))
+ self.assertTrue(Port.is_test_file(filesystem, '', 'test-ref-test.html'))
+ self.assertFalse(Port.is_test_file(filesystem, '', 'foo.png'))
+ self.assertFalse(Port.is_test_file(filesystem, '', 'foo-expected.html'))
+ self.assertFalse(Port.is_test_file(filesystem, '', 'foo-expected.svg'))
+ self.assertFalse(Port.is_test_file(filesystem, '', 'foo-expected.xht'))
+ self.assertFalse(Port.is_test_file(filesystem, '', 'foo-expected-mismatch.html'))
+ self.assertFalse(Port.is_test_file(filesystem, '', 'foo-expected-mismatch.svg'))
+ self.assertFalse(Port.is_test_file(filesystem, '', 'foo-expected-mismatch.xhtml'))
+ self.assertFalse(Port.is_test_file(filesystem, '', 'foo-ref.html'))
+ self.assertFalse(Port.is_test_file(filesystem, '', 'foo-notref.html'))
+ self.assertFalse(Port.is_test_file(filesystem, '', 'foo-notref.xht'))
+ self.assertFalse(Port.is_test_file(filesystem, '', 'foo-ref.xhtml'))
+ self.assertFalse(Port.is_test_file(filesystem, '', 'ref-foo.html'))
+ self.assertFalse(Port.is_test_file(filesystem, '', 'notref-foo.xhr'))
def test_parse_reftest_list(self):
port = self.make_port(with_tests=True)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/builders.py b/Tools/Scripts/webkitpy/layout_tests/port/builders.py
index cdc9e5b..63621f8 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/builders.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/builders.py
@@ -58,52 +58,10 @@
"WebKit Mac10.7": {"port_name": "chromium-mac-lion", "is_debug": False},
"WebKit Mac10.7 (dbg)": {"port_name": "chromium-mac-lion", "is_debug": True},
"WebKit Mac10.8": {"port_name": "chromium-mac-mountainlion", "is_debug": False},
-
- # These builders are on build.webkit.org.
- "Apple MountainLion Release WK1 (Tests)": {"port_name": "mac-mountainlion", "is_debug": False, "rebaseline_override_dir": "mac"},
- "Apple MountainLion Debug WK1 (Tests)": {"port_name": "mac-mountainlion", "is_debug": True, "rebaseline_override_dir": "mac"},
- "Apple MountainLion Release WK2 (Tests)": {"port_name": "mac-mountainlion-wk2", "is_debug": False, "rebaseline_override_dir": "mac"},
- "Apple MountainLion Debug WK2 (Tests)": {"port_name": "mac-mountainlion-wk2", "is_debug": True, "rebaseline_override_dir": "mac"},
- "Apple Lion Release WK1 (Tests)": {"port_name": "mac-lion", "is_debug": False},
- "Apple Lion Debug WK1 (Tests)": {"port_name": "mac-lion", "is_debug": True},
- "Apple Lion Release WK2 (Tests)": {"port_name": "mac-lion-wk2", "is_debug": False},
- "Apple Lion Debug WK2 (Tests)": {"port_name": "mac-lion-wk2", "is_debug": True},
-
- "Apple Win XP Debug (Tests)": {"port_name": "win-xp", "is_debug": True},
- # FIXME: Remove rebaseline_override_dir once there is an Apple buildbot that corresponds to platform/win.
- "Apple Win 7 Release (Tests)": {"port_name": "win-7sp0", "is_debug": False, "rebaseline_override_dir": "win"},
-
- "GTK Linux 32-bit Release": {"port_name": "gtk", "is_debug": False},
- "GTK Linux 64-bit Debug": {"port_name": "gtk", "is_debug": True},
- "GTK Linux 64-bit Release": {"port_name": "gtk", "is_debug": False},
- "GTK Linux 64-bit Release WK2 (Tests)": {"port_name": "gtk-wk2", "is_debug": False},
-
- # FIXME: Remove rebaseline_override_dir once there are Qt bots for all the platform/qt-* directories.
- "Qt Linux Release": {"port_name": "qt-linux", "is_debug": False, "rebaseline_override_dir": "qt"},
-
- "EFL Linux 64-bit Release": {"port_name": "efl", "is_debug": False},
- "EFL Linux 64-bit Release WK2": {"port_name": "efl-wk2", "is_debug": False},
- "EFL Linux 64-bit Debug WK2": {"port_name": "efl-wk2", "is_debug": True},
-}
-
-
-_fuzzy_matches = {
- # These builders are on build.webkit.org.
- r"SnowLeopard": "mac-snowleopard",
- r"Apple Lion": "mac-lion",
- r"Windows": "win",
- r"GTK": "gtk",
- r"Qt": "qt",
- r"Chromium Mac": "chromium-mac",
- r"Chromium Linux": "chromium-linux",
- r"Chromium Win": "chromium-win",
}
_ports_without_builders = [
- "qt-mac",
- "qt-win",
- "qt-wk2",
# FIXME: Move to _extact_matches.
"chromium-android",
]
@@ -130,12 +88,7 @@
def port_name_for_builder_name(builder_name):
- if builder_name in _exact_matches:
- return _exact_matches[builder_name]["port_name"]
-
- for regexp, port_name in _fuzzy_matches.items():
- if re.match(regexp, builder_name):
- return port_name
+ return _exact_matches[builder_name]["port_name"]
def builder_name_for_port_name(target_port_name):
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
index aa4d30c..ce0564d 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
@@ -60,7 +60,10 @@
('lucid', 'x86_64'),
# FIXME: Technically this should be 'arm', but adding a third architecture type breaks TestConfigurationConverter.
# If we need this to be 'arm' in the future, then we first have to fix TestConfigurationConverter.
- ('icecreamsandwich', 'x86'))
+ # FIXME: Until we have an android bot to do rebaselines, we need to not include it in ALL_SYSTEMS
+ # because otherwise rebaselines won't correclty remove lines from TestExpectations.
+ #('icecreamsandwich', 'x86'),
+ )
ALL_BASELINE_VARIANTS = [
'chromium-mac-mountainlion', 'chromium-mac-lion', 'chromium-mac-snowleopard',
@@ -81,6 +84,10 @@
FALLBACK_PATHS = {}
@classmethod
+ def latest_platform_fallback_path(cls):
+ return cls.FALLBACK_PATHS[cls.SUPPORTED_VERSIONS[-1]]
+
+ @classmethod
def _static_build_path(cls, filesystem, build_directory, chromium_base, webkit_base, configuration, comps):
if build_directory:
return filesystem.join(build_directory, configuration, *comps)
@@ -122,6 +129,15 @@
def is_chromium(self):
return True
+ def default_child_processes(self):
+ default_count = super(ChromiumPort, self).default_child_processes()
+ # Since content_shell spawns multiple subprocesses, we need to reduce
+ # the number of running processes.
+ if self.driver_name() == self.CONTENT_SHELL_NAME:
+ default_count = int(.75 * default_count)
+
+ return default_count
+
def default_max_locked_shards(self):
"""Return the number of "locked" shards to run in parallel (like the http tests)."""
max_locked_shards = int(self.default_child_processes()) / 4
@@ -351,12 +367,9 @@
return True
def _port_specific_expectations_files(self):
- paths = [self.path_to_test_expectations_file()]
- skia_expectations_path = self.path_from_chromium_base('skia', 'skia_test_expectations.txt')
- # FIXME: we should probably warn if this file is missing in some situations.
- # See the discussion in webkit.org/b/97699.
- if self._filesystem.exists(skia_expectations_path):
- paths.append(skia_expectations_path)
+ paths = []
+ paths.append(self.path_from_chromium_base('skia', 'skia_test_expectations.txt'))
+ paths.append(self._filesystem.join(self.layout_tests_dir(), 'NeverFixTests'))
builder_name = self.get_option('builder_name', 'DUMMY_BUILDER_NAME')
if builder_name == 'DUMMY_BUILDER_NAME' or '(deps)' in builder_name or builder_name in self.try_builder_names:
@@ -388,31 +401,31 @@
def virtual_test_suites(self):
return [
- VirtualTestSuite('platform/chromium/virtual/gpu/fast/canvas',
+ VirtualTestSuite('virtual/gpu/fast/canvas',
'fast/canvas',
['--enable-accelerated-2d-canvas']),
- VirtualTestSuite('platform/chromium/virtual/gpu/canvas/philip',
+ VirtualTestSuite('virtual/gpu/canvas/philip',
'canvas/philip',
['--enable-accelerated-2d-canvas']),
- VirtualTestSuite('platform/chromium/virtual/threaded/compositing/visibility',
+ VirtualTestSuite('virtual/threaded/compositing/visibility',
'compositing/visibility',
['--enable-threaded-compositing']),
- VirtualTestSuite('platform/chromium/virtual/threaded/compositing/webgl',
+ VirtualTestSuite('virtual/threaded/compositing/webgl',
'compositing/webgl',
['--enable-threaded-compositing']),
- VirtualTestSuite('platform/chromium/virtual/gpu/fast/hidpi',
+ VirtualTestSuite('virtual/gpu/fast/hidpi',
'fast/hidpi',
['--force-compositing-mode']),
- VirtualTestSuite('platform/chromium/virtual/softwarecompositing',
+ VirtualTestSuite('virtual/softwarecompositing',
'compositing',
['--enable-software-compositing']),
- VirtualTestSuite('platform/chromium/virtual/deferred/fast/images',
+ VirtualTestSuite('virtual/deferred/fast/images',
'fast/images',
['--enable-deferred-image-decoding', '--enable-per-tile-painting', '--force-compositing-mode']),
- VirtualTestSuite('platform/chromium/virtual/gpu/compositedscrolling/overflow',
+ VirtualTestSuite('virtual/gpu/compositedscrolling/overflow',
'compositing/overflow',
['--enable-accelerated-overflow-scroll']),
- VirtualTestSuite('platform/chromium/virtual/gpu/compositedscrolling/scrollbars',
+ VirtualTestSuite('virtual/gpu/compositedscrolling/scrollbars',
'scrollbars',
['--enable-accelerated-overflow-scroll']),
]
@@ -429,8 +442,8 @@
def _build_path_with_configuration(self, configuration, *comps):
# Note that we don't implement --root or do the option caching that the
- # base class does, because chromium doesn't use 'webkit-build-directory' and
- # hence finding the right directory is relatively fast.
+ # base class does, because finding the right directory is relatively
+ # fast.
configuration = configuration or self.get_option('configuration')
return self._static_build_path(self._filesystem, self.get_option('build_directory'),
self.path_from_chromium_base(), self.path_from_webkit_base(), configuration, comps)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py
index b095463..046317b 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py
@@ -36,6 +36,7 @@
import time
from webkitpy.layout_tests.port import chromium
+from webkitpy.layout_tests.port import chromium_linux
from webkitpy.layout_tests.port import driver
from webkitpy.layout_tests.port import factory
from webkitpy.layout_tests.port import server_process
@@ -47,26 +48,18 @@
# source root directory of Chromium.
# This path is defined in Chromium's base/test/test_support_android.cc.
DEVICE_SOURCE_ROOT_DIR = '/data/local/tmp/'
-COMMAND_LINE_FILE = DEVICE_SOURCE_ROOT_DIR + 'chrome-native-tests-command-line'
-# The directory to put tools and resources of DumpRenderTree.
-# If change this, must also change Tools/DumpRenderTree/chromium/TestShellAndroid.cpp
-# and Chromium's webkit/support/platform_support_android.cc.
-DEVICE_DRT_DIR = DEVICE_SOURCE_ROOT_DIR + 'drt/'
-DEVICE_FORWARDER_PATH = DEVICE_DRT_DIR + 'forwarder'
-
-# Path on the device where the test framework will create the fifo pipes.
-DEVICE_FIFO_PATH = '/data/data/org.chromium.native_test/files/'
-
-DRT_APP_PACKAGE = 'org.chromium.native_test'
-DRT_ACTIVITY_FULL_NAME = DRT_APP_PACKAGE + '/.ChromeNativeTestActivity'
-DRT_APP_CACHE_DIR = DEVICE_DRT_DIR + 'cache/'
-DRT_LIBRARY_NAME = 'libDumpRenderTree.so'
+# The layout tests directory on device, which has two usages:
+# 1. as a virtual path in file urls that will be bridged to HTTP.
+# 2. pointing to some files that are pushed to the device for tests that
+# don't work on file-over-http (e.g. blob protocol tests).
+DEVICE_WEBKIT_BASE_DIR = DEVICE_SOURCE_ROOT_DIR + 'third_party/WebKit/'
+DEVICE_LAYOUT_TESTS_DIR = DEVICE_WEBKIT_BASE_DIR + 'LayoutTests/'
SCALING_GOVERNORS_PATTERN = "/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor"
KPTR_RESTRICT_PATH = "/proc/sys/kernel/kptr_restrict"
-# All the test cases are still served to DumpRenderTree through file protocol,
+# All the test cases are still served to the test runner through file protocol,
# but we use a file-to-http feature to bridge the file request to host's http
# server to get the real test files and corresponding resources.
# See webkit/support/platform_support_android.cc for the other side of this bridge.
@@ -82,10 +75,9 @@
MS_TRUETYPE_FONTS_DIR = '/usr/share/fonts/truetype/msttcorefonts/'
MS_TRUETYPE_FONTS_PACKAGE = 'ttf-mscorefonts-installer'
-# Timeout in seconds to wait for start/stop of DumpRenderTree.
-DRT_START_STOP_TIMEOUT_SECS = 10
+# Timeout in seconds to wait for starting/stopping the driver.
+DRIVER_START_STOP_TIMEOUT_SECS = 10
-# List of fonts that layout tests expect, copied from DumpRenderTree/chromium/TestShellX11.cpp.
HOST_FONT_FILES = [
[[MS_TRUETYPE_FONTS_DIR], 'Arial.ttf', MS_TRUETYPE_FONTS_PACKAGE],
[[MS_TRUETYPE_FONTS_DIR], 'Arial_Bold.ttf', MS_TRUETYPE_FONTS_PACKAGE],
@@ -126,15 +118,6 @@
[['/usr/share/fonts/truetype/ttf-indic-fonts-core/', '/usr/share/fonts/truetype/ttf-punjabi-fonts/'], 'lohit_pa.ttf', 'ttf-indic-fonts-core'],
]
-DEVICE_FONTS_DIR = DEVICE_DRT_DIR + 'fonts/'
-
-# The layout tests directory on device, which has two usages:
-# 1. as a virtual path in file urls that will be bridged to HTTP.
-# 2. pointing to some files that are pushed to the device for tests that
-# don't work on file-over-http (e.g. blob protocol tests).
-DEVICE_WEBKIT_BASE_DIR = DEVICE_SOURCE_ROOT_DIR + 'third_party/WebKit/'
-DEVICE_LAYOUT_TESTS_DIR = DEVICE_WEBKIT_BASE_DIR + 'LayoutTests/'
-
# Test resources that need to be accessed as files directly.
# Each item can be the relative path of a directory or a file.
TEST_RESOURCES_TO_PUSH = [
@@ -158,18 +141,176 @@
MD5SUM_DEVICE_FILE_NAME = 'md5sum_bin'
MD5SUM_DEVICE_PATH = '/data/local/tmp/' + MD5SUM_DEVICE_FILE_NAME
+# Shared pieces of information for the two supported test runners.
+class SharedDriverDetails(object):
+ def device_cache_directory(self):
+ return self.device_directory() + 'cache/'
+ def device_fonts_directory(self):
+ return self.device_directory() + 'fonts/'
+ def device_forwarder_path(self):
+ return self.device_directory() + 'forwarder'
+ def device_fifo_directory(self):
+ return '/data/data/' + self.package_name() + '/files/'
+
+# Information required when running layout tests using DumpRenderTree as the test runner.
+class DumpRenderTreeDriverDetails(SharedDriverDetails):
+ def apk_name(self):
+ return 'DumpRenderTree_apk/DumpRenderTree-debug.apk'
+ def package_name(self):
+ return 'org.chromium.native_test'
+ def activity_name(self):
+ return self.package_name() + '/.ChromeNativeTestActivity'
+ def library_name(self):
+ return 'libDumpRenderTree.so'
+ def additional_resources(self):
+ return ['DumpRenderTree.pak', 'DumpRenderTree_resources']
+ def command_line_file(self):
+ return '/data/local/tmp/chrome-native-tests-command-line'
+ def additional_command_line_flags(self):
+ return ['--create-stdin-fifo', '--separate-stderr-fifo']
+ def device_directory(self):
+ return DEVICE_SOURCE_ROOT_DIR + 'drt/'
+
+# Information required when running layout tests using content_shell as the test runner.
+class ContentShellDriverDetails(SharedDriverDetails):
+ def apk_name(self):
+ return 'apks/ContentShell.apk'
+ def package_name(self):
+ return 'org.chromium.content_shell_apk'
+ def activity_name(self):
+ return self.package_name() + '/.ContentShellActivity'
+ def library_name(self):
+ return 'libcontent_shell_content_view.so'
+ def additional_resources(self):
+ return ['content_resources.pak', 'shell_resources.pak']
+ def command_line_file(self):
+ return '/data/local/tmp/content-shell-command-line'
+ def additional_command_line_flags(self):
+ return []
+ def device_directory(self):
+ return DEVICE_SOURCE_ROOT_DIR + 'content_shell/'
+
+# The AndroidCommands class encapsulates commands to communicate with an attached device.
+class AndroidCommands(object):
+ _adb_command_path = None
+ _adb_command_path_options = []
+
+ def __init__(self, executive, device_serial):
+ self._executive = executive
+ self._device_serial = device_serial
+
+ # Local public methods.
+
+ def file_exists(self, full_path):
+ assert full_path.startswith('/')
+ return self.run(['shell', 'ls', full_path]).strip() == full_path
+
+ def push(self, host_path, device_path, ignore_error=False):
+ return self.run(['push', host_path, device_path], ignore_error=ignore_error)
+
+ def pull(self, device_path, host_path, ignore_error=False):
+ return self.run(['pull', device_path, host_path], ignore_error=ignore_error)
+
+ def restart_as_root(self):
+ output = self.run(['root'])
+ if 'adbd is already running as root' in output:
+ return
+
+ elif not 'restarting adbd as root' in output:
+ self._log_error('Unrecognized output from adb root: %s' % output)
+
+ self.run(['wait-for-device'])
+
+ def run(self, command, ignore_error=False):
+ self._log_debug('Run adb command: ' + str(command))
+ if ignore_error:
+ error_handler = self._executive.ignore_error
+ else:
+ error_handler = None
+
+ result = self._executive.run_command(self.adb_command() + command,
+ error_handler=error_handler)
+
+ # We limit the length to avoid outputting too verbose commands, such as "adb logcat".
+ self._log_debug('Run adb result: ' + result[:80])
+ return result
+
+ def get_serial(self):
+ return self._device_serial
+
+ def adb_command(self):
+ return [AndroidCommands.adb_command_path(self._executive), '-s', self._device_serial]
+
+ @staticmethod
+ def set_adb_command_path_options(paths):
+ AndroidCommands._adb_command_path_options = paths
+
+ @staticmethod
+ def adb_command_path(executive):
+ if AndroidCommands._adb_command_path:
+ return AndroidCommands._adb_command_path
+
+ assert AndroidCommands._adb_command_path_options, 'No commands paths have been set to look for the "adb" command.'
+
+ command_path = None
+ command_version = None
+ for path_option in AndroidCommands._adb_command_path_options:
+ path_version = AndroidCommands._determine_adb_version(path_option, executive)
+ if not path_version:
+ continue
+ if command_version != None and path_version < command_version:
+ continue
+
+ command_path = path_option
+ command_version = path_version
+
+ assert command_path, 'Unable to locate the "adb" command. Are you using an Android checkout of Chromium?'
+
+ AndroidCommands._adb_command_path = command_path
+ return command_path
+
+ @staticmethod
+ def get_devices(executive):
+ re_device = re.compile('^([a-zA-Z0-9_:.-]+)\tdevice$', re.MULTILINE)
+ result = executive.run_command([AndroidCommands.adb_command_path(executive), 'devices'],
+ error_handler=executive.ignore_error)
+ devices = re_device.findall(result)
+ if not devices:
+ raise AssertionError('No devices attached. Result of "adb devices": %s' % result)
+
+ return devices
+
+ # Local private methods.
+
+ def _log_error(self, message):
+ _log.error('[%s] %s' % (self._device_serial, message))
+
+ def _log_debug(self, message):
+ _log.debug('[%s] %s' % (self._device_serial, message))
+
+ @staticmethod
+ def _determine_adb_version(adb_command_path, executive):
+ re_version = re.compile('^.*version ([\d\.]+)$')
+ try:
+ output = executive.run_command([adb_command_path, 'version'], error_handler=executive.ignore_error)
+ except OSError:
+ return None
+
+ result = re_version.match(output)
+ if not output or not result:
+ return None
+
+ return [int(n) for n in result.group(1).split('.')]
+
class ChromiumAndroidPort(chromium.ChromiumPort):
port_name = 'chromium-android'
# Avoid initializing the adb path [worker count]+1 times by storing it as a static member.
_adb_path = None
- FALLBACK_PATHS = [
- 'chromium-android',
- 'chromium-linux',
- 'chromium-win',
- 'chromium',
- ]
+ SUPPORTED_VERSIONS = ('android')
+
+ FALLBACK_PATHS = { 'android': [ 'chromium-android' ] + chromium_linux.ChromiumLinuxPort.latest_platform_fallback_path() }
def __init__(self, host, port_name, **kwargs):
super(ChromiumAndroidPort, self).__init__(host, port_name, **kwargs)
@@ -180,18 +321,39 @@
self._host_port = factory.PortFactory(host).get('chromium', **kwargs)
self._server_process_constructor = self._android_server_process_constructor
- if hasattr(self._options, 'adb_device'):
- self._devices = self._options.adb_device
+ if self.driver_name() == 'content_shell':
+ self._driver_details = ContentShellDriverDetails()
+ else:
+ self._driver_details = DumpRenderTreeDriverDetails()
+
+ if hasattr(self._options, 'adb_device') and len(self._options.adb_device):
+ self._devices = [self._options.adb_device]
else:
self._devices = []
- @staticmethod
- def _android_server_process_constructor(port, server_name, cmd_line, env=None):
- return server_process.ServerProcess(port, server_name, cmd_line, env,
- universal_newlines=True, treat_no_data_as_crash=True)
+ AndroidCommands.set_adb_command_path_options(['adb',
+ self.path_from_chromium_base('third_party', 'android_tools', 'sdk', 'platform-tools', 'adb')])
+
+ # Local public methods.
+ def get_device_serial(self, worker_number):
+ if not self._devices:
+ self._devices = AndroidCommands.get_devices(self._executive)
+ if worker_number >= len(self._devices):
+ raise AssertionError('Worker number exceeds available number of devices')
+ return self._devices[worker_number]
+
+ def path_to_forwarder(self):
+ return self._build_path('forwarder')
+
+ def path_to_md5sum(self):
+ return self._build_path(MD5SUM_DEVICE_FILE_NAME)
+
+ # Overridden public methods.
+ def buildbot_archives_baselines(self):
+ return False
def additional_drt_flag(self):
- # The Chromium port for Android always uses the hardware GPU path.
+ # Chromium for Android always uses the hardware GPU path.
return ['--encode-binary', '--enable-hardware-gpu',
'--force-compositing-mode',
'--enable-accelerated-fixed-position']
@@ -203,14 +365,17 @@
return 10 * 1000
def driver_stop_timeout(self):
- # DRT doesn't respond to closing stdin, so we might as well stop the driver immediately.
+ # The driver doesn't respond to closing stdin, so we might as well stop the driver immediately.
return 0.0
def default_child_processes(self):
- return len(self._get_devices())
+ if self._devices:
+ return len(self._devices)
+
+ return len(AndroidCommands.get_devices(self._executive))
def default_baseline_search_path(self):
- return map(self._webkit_baseline_path, self.FALLBACK_PATHS)
+ return map(self._webkit_baseline_path, self.FALLBACK_PATHS['android'])
def check_wdiff(self, logging=True):
return self._host_port.check_wdiff(logging)
@@ -239,16 +404,9 @@
return False
return True
- def _port_specific_expectations_files(self):
- # LayoutTests/platform/chromium-android/TestExpectations should contain only the rules to
- # skip tests for the features not supported or not testable on Android.
- # Other rules should be in LayoutTests/platform/chromium/TestExpectations.
- android_expectations_file = self.path_from_webkit_base('LayoutTests', 'platform', 'chromium-android', 'TestExpectations')
- return super(ChromiumAndroidPort, self)._port_specific_expectations_files() + [android_expectations_file]
-
def requires_http_server(self):
"""Chromium Android runs tests on devices, and uses the HTTP server to
- serve the actual layout tests to DumpRenderTree."""
+ serve the actual layout tests to the test driver."""
return True
def start_http_server(self, additional_dirs=None, number_of_servers=0):
@@ -261,41 +419,23 @@
def create_driver(self, worker_number, no_timeout=False):
# We don't want the default DriverProxy which is not compatible with our driver.
# See comments in ChromiumAndroidDriver.start().
- return ChromiumAndroidDriver(self, worker_number, pixel_tests=self.get_option('pixel_tests'),
- # Force no timeout to avoid DumpRenderTree timeouts before NRWT.
+ return ChromiumAndroidDriver(self, worker_number, pixel_tests=self.get_option('pixel_tests'), driver_details=self._driver_details,
+ # Force no timeout to avoid test driver timeouts before NRWT.
no_timeout=True)
def driver_cmd_line(self):
- # Override to return the actual DumpRenderTree command line.
- return self.create_driver(0)._drt_cmd_line(self.get_option('pixel_tests'), [])
+ # Override to return the actual test driver's command line.
+ return self.create_driver(0)._android_driver_cmd_line(self.get_option('pixel_tests'), [])
- def path_to_adb(self):
- if ChromiumAndroidPort._adb_path:
- return ChromiumAndroidPort._adb_path
+ # Overridden protected methods.
- provided_adb_path = self.path_from_chromium_base('third_party', 'android_tools', 'sdk', 'platform-tools', 'adb')
+ def _port_specific_expectations_files(self):
+ # LayoutTests/platform/chromium-android/TestExpectations should contain only the rules to
+ # skip tests for the features not supported or not testable on Android.
+ # Other rules should be in LayoutTests/TestExpectations.
+ android_expectations_file = self.path_from_webkit_base('LayoutTests', 'platform', 'chromium-android', 'TestExpectations')
+ return super(ChromiumAndroidPort, self)._port_specific_expectations_files() + [android_expectations_file]
- path_version = self._determine_adb_version('adb')
- provided_version = self._determine_adb_version(provided_adb_path)
- assert provided_version, 'The checked in Android SDK is missing. Are you sure you ran update-webkit --chromium-android?'
-
- if not path_version:
- ChromiumAndroidPort._adb_path = provided_adb_path
- elif provided_version > path_version:
- _log.warning('The "adb" version in your path is older than the one checked in, consider updating your local Android SDK. Using the checked in one.')
- ChromiumAndroidPort._adb_path = provided_adb_path
- else:
- ChromiumAndroidPort._adb_path = 'adb'
-
- return ChromiumAndroidPort._adb_path
-
- def path_to_forwarder(self):
- return self._build_path('forwarder')
-
- def path_to_md5sum(self):
- return self._build_path(MD5SUM_DEVICE_FILE_NAME)
-
- # Overridden private functions.
def _build_path(self, *comps):
return self._host_port._build_path(*comps)
@@ -310,7 +450,7 @@
return self._host_port._path_to_apache_config_file()
def _path_to_driver(self, configuration=None):
- return self._build_path_with_configuration(configuration, 'DumpRenderTree_apk/DumpRenderTree-debug.apk')
+ return self._build_path_with_configuration(configuration, self._driver_details.apk_name())
def _path_to_helper(self):
return None
@@ -336,56 +476,36 @@
def _driver_class(self):
return ChromiumAndroidDriver
- # Local private functions.
+ # Local private methods.
- def _determine_adb_version(self, adb_path):
- re_version = re.compile('^.*version ([\d\.]+)$')
- try:
- output = self._executive.run_command([adb_path, 'version'], error_handler=self._executive.ignore_error)
- except OSError:
- return None
- result = re_version.match(output)
- if not output or not result:
- return None
- return [int(n) for n in result.group(1).split('.')]
-
- def _get_devices(self):
- if not self._devices:
- re_device = re.compile('^([a-zA-Z0-9_:.-]+)\tdevice$', re.MULTILINE)
- result = self._executive.run_command([self.path_to_adb(), 'devices'], error_handler=self._executive.ignore_error)
- self._devices = re_device.findall(result)
- if not self._devices:
- raise AssertionError('No devices attached. Result of "adb devices": %s' % result)
- return self._devices
-
- def _get_device_serial(self, worker_number):
- devices = self._get_devices()
- if worker_number >= len(devices):
- raise AssertionError('Worker number exceeds available number of devices')
- return devices[worker_number]
+ @staticmethod
+ def _android_server_process_constructor(port, server_name, cmd_line, env=None):
+ return server_process.ServerProcess(port, server_name, cmd_line, env,
+ universal_newlines=True, treat_no_data_as_crash=True)
class AndroidPerf(SingleFileOutputProfiler):
_cached_perf_host_path = None
_have_searched_for_perf_host = False
- def __init__(self, host, executable_path, output_dir, adb_path, device_serial, symfs_path, kallsyms_path, identifier=None):
+ def __init__(self, host, executable_path, output_dir, android_commands, symfs_path, kallsyms_path, identifier=None):
super(AndroidPerf, self).__init__(host, executable_path, output_dir, "data", identifier)
- self._device_serial = device_serial
- self._adb_command = [adb_path, '-s', self._device_serial]
+ self._android_commands = android_commands
self._perf_process = None
self._symfs_path = symfs_path
self._kallsyms_path = kallsyms_path
def check_configuration(self):
# Check that perf is installed
- if not self._file_exists_on_device('/system/bin/perf'):
- print "Cannot find /system/bin/perf on device %s" % self._device_serial
+ if not self._android_commands.file_exists('/system/bin/perf'):
+ print "Cannot find /system/bin/perf on device %s" % self._android_commands.get_serial()
return False
+
# Check that the device is a userdebug build (or at least has the necessary libraries).
- if self._run_adb_command(['shell', 'getprop', 'ro.build.type']).strip() != 'userdebug':
- print "Device %s is not flashed with a userdebug build of Android" % self._device_serial
+ if self._android_commands.run(['shell', 'getprop', 'ro.build.type']).strip() != 'userdebug':
+ print "Device %s is not flashed with a userdebug build of Android" % self._android_commands.get_serial()
return False
+
# FIXME: Check that the binary actually is perf-able (has stackframe pointers)?
# objdump -s a function and make sure it modifies the fp?
# Instruct users to rebuild after export GYP_DEFINES="profiling=1 $GYP_DEFINES"
@@ -401,7 +521,7 @@
and requires libefl, libebl, libdw, and libdwfl available in:
https://android.googlesource.com/platform/external/elfutils/
-DumpRenderTree must be built with profiling=1, make sure you've done:
+The test driver must be built with profiling=1, make sure you've done:
export GYP_DEFINES="profiling=1 $GYP_DEFINES"
update-webkit --chromium-android
build-webkit --chromium-android
@@ -410,18 +530,11 @@
http://goto.google.com/cr-android-perf-howto
"""
- def _file_exists_on_device(self, full_file_path):
- assert full_file_path.startswith('/')
- return self._run_adb_command(['shell', 'ls', full_file_path]).strip() == full_file_path
-
- def _run_adb_command(self, cmd):
- return self._host.executive.run_command(self._adb_command + cmd)
-
def attach_to_pid(self, pid):
assert(pid)
assert(self._perf_process == None)
# FIXME: This can't be a fixed timeout!
- cmd = self._adb_command + ['shell', 'perf', 'record', '-g', '-p', pid, 'sleep', 30]
+ cmd = self._android_commands.adb_command() + ['shell', 'perf', 'record', '-g', '-p', pid, 'sleep', 30]
self._perf_process = self._host.executive.popen(cmd)
def _perf_version_string(self, perf_path):
@@ -455,7 +568,8 @@
if perf_exitcode != 0:
print "Perf failed (exit code: %i), can't process results." % perf_exitcode
return
- self._run_adb_command(['pull', '/data/perf.data', self._output_path])
+
+ self._android_commands.pull('/data/perf.data', self._output_path)
perfhost_path = self._perfhost_path()
perfhost_report_command = [
@@ -490,20 +604,21 @@
class ChromiumAndroidDriver(driver.Driver):
- def __init__(self, port, worker_number, pixel_tests, no_timeout=False):
+ def __init__(self, port, worker_number, pixel_tests, driver_details, no_timeout=False):
super(ChromiumAndroidDriver, self).__init__(port, worker_number, pixel_tests, no_timeout)
self._cmd_line = None
- self._in_fifo_path = DEVICE_FIFO_PATH + 'stdin.fifo'
- self._out_fifo_path = DEVICE_FIFO_PATH + 'test.fifo'
- self._err_fifo_path = DEVICE_FIFO_PATH + 'stderr.fifo'
+ self._in_fifo_path = driver_details.device_fifo_directory() + 'stdin.fifo'
+ self._out_fifo_path = driver_details.device_fifo_directory() + 'test.fifo'
+ self._err_fifo_path = driver_details.device_fifo_directory() + 'stderr.fifo'
self._read_stdout_process = None
self._read_stderr_process = None
self._forwarder_process = None
self._has_setup = False
self._original_governors = {}
self._original_kptr_restrict = None
- self._device_serial = port._get_device_serial(worker_number)
- self._adb_command_base = None
+
+ self._android_commands = AndroidCommands(port._executive, port.get_device_serial(worker_number))
+ self._driver_details = driver_details
# FIXME: If we taught ProfileFactory about "target" devices we could
# just use the logic in Driver instead of duplicating it here.
@@ -513,7 +628,7 @@
kallsyms_path = self._update_kallsyms_cache(symfs_path)
# FIXME: We should pass this some sort of "Bridge" object abstraction around ADB instead of a path/device pair.
self._profiler = AndroidPerf(self._port.host, self._port._path_to_driver(), self._port.results_directory(),
- self._port.path_to_adb(), self._device_serial, symfs_path, kallsyms_path)
+ self._android_commands, symfs_path, kallsyms_path)
# FIXME: This is a layering violation and should be moved to Port.check_sys_deps
# once we have an abstraction around an adb_path/device_serial pair to make it
# easy to make these class methods on AndroidPerf.
@@ -528,18 +643,18 @@
super(ChromiumAndroidDriver, self).__del__()
def _update_kallsyms_cache(self, output_dir):
- kallsyms_name = "%s-kallsyms" % self._device_serial
+ kallsyms_name = "%s-kallsyms" % self._android_commands.get_serial()
kallsyms_cache_path = self._port.host.filesystem.join(output_dir, kallsyms_name)
- self._restart_adb_as_root()
+ self._android_commands.restart_as_root()
- saved_kptr_restrict = self._run_adb_command(['shell', 'cat', KPTR_RESTRICT_PATH]).strip()
- self._run_adb_command(['shell', 'echo', '0', '>', KPTR_RESTRICT_PATH])
+ saved_kptr_restrict = self._android_commands.run(['shell', 'cat', KPTR_RESTRICT_PATH]).strip()
+ self._android_commands.run(['shell', 'echo', '0', '>', KPTR_RESTRICT_PATH])
print "Updating kallsyms file (%s) from device" % kallsyms_cache_path
- self._pull_from_device("/proc/kallsyms", kallsyms_cache_path)
+ self._android_commands.pull("/proc/kallsyms", kallsyms_cache_path)
- self._run_adb_command(['shell', 'echo', saved_kptr_restrict, '>', KPTR_RESTRICT_PATH])
+ self._android_commands.run(['shell', 'echo', saved_kptr_restrict, '>', KPTR_RESTRICT_PATH])
return kallsyms_cache_path
@@ -556,8 +671,8 @@
# find the installed path, and the path of the symboled built library
# FIXME: We should get the install path from the device!
- symfs_library_path = fs.join(symfs_path, "data/app-lib/%s-1/%s" % (DRT_APP_PACKAGE, DRT_LIBRARY_NAME))
- built_library_path = self._port._build_path('lib', DRT_LIBRARY_NAME)
+ symfs_library_path = fs.join(symfs_path, "data/app-lib/%s-1/%s" % (self._driver_details.package_name(), self._driver_details.library_name()))
+ built_library_path = self._port._build_path('lib', self._driver_details.library_name())
assert(fs.exists(built_library_path))
# FIXME: Ideally we'd check the sha1's first and make a soft-link instead of copying (since we probably never care about windows).
@@ -569,8 +684,8 @@
def _setup_md5sum_and_push_data_if_needed(self):
self._md5sum_path = self._port.path_to_md5sum()
- if not self._file_exists_on_device(MD5SUM_DEVICE_PATH):
- if not self._push_to_device(self._md5sum_path, MD5SUM_DEVICE_PATH):
+ if not self._android_commands.file_exists(MD5SUM_DEVICE_PATH):
+ if not self._android_commands.push(self._md5sum_path, MD5SUM_DEVICE_PATH):
raise AssertionError('Could not push md5sum to device')
self._push_executable()
@@ -582,32 +697,32 @@
if self._has_setup:
return
- self._restart_adb_as_root()
+ self._android_commands.restart_as_root()
self._setup_md5sum_and_push_data_if_needed()
self._has_setup = True
self._setup_performance()
# Required by webkit_support::GetWebKitRootDirFilePath().
# Other directories will be created automatically by adb push.
- self._run_adb_command(['shell', 'mkdir', '-p', DEVICE_SOURCE_ROOT_DIR + 'chrome'])
+ self._android_commands.run(['shell', 'mkdir', '-p', DEVICE_SOURCE_ROOT_DIR + 'chrome'])
- # Allow the DumpRenderTree app to fully access the directory.
+ # Allow the test driver to get full read and write access to the directory.
# The native code needs the permission to write temporary files and create pipes here.
- self._run_adb_command(['shell', 'mkdir', '-p', DEVICE_DRT_DIR])
- self._run_adb_command(['shell', 'chmod', '777', DEVICE_DRT_DIR])
+ self._android_commands.run(['shell', 'mkdir', '-p', self._driver_details.device_directory()])
+ self._android_commands.run(['shell', 'chmod', '777', self._driver_details.device_directory()])
# Delete the disk cache if any to ensure a clean test run.
# This is like what's done in ChromiumPort.setup_test_run but on the device.
- self._run_adb_command(['shell', 'rm', '-r', DRT_APP_CACHE_DIR])
+ self._android_commands.run(['shell', 'rm', '-r', self._driver_details.device_cache_directory()])
def _log_error(self, message):
- _log.error('[%s] %s' % (self._device_serial, message))
+ _log.error('[%s] %s' % (self._android_commands.get_serial(), message))
def _log_debug(self, message):
- _log.debug('[%s] %s' % (self._device_serial, message))
+ _log.debug('[%s] %s' % (self._android_commands.get_serial(), message))
def _abort(self, message):
- raise AssertionError('[%s] %s' % (self._device_serial, message))
+ raise AssertionError('[%s] %s' % (self._android_commands.get_serial(), message))
@staticmethod
def _extract_hashes_from_md5sum_output(md5sum_output):
@@ -617,36 +732,39 @@
def _push_file_if_needed(self, host_file, device_file):
assert os.path.exists(host_file)
device_hashes = self._extract_hashes_from_md5sum_output(
- self._port.host.executive.popen(self._adb_command() + ['shell', MD5SUM_DEVICE_PATH, device_file],
+ self._port.host.executive.popen(self._android_commands.adb_command() + ['shell', MD5SUM_DEVICE_PATH, device_file],
stdout=subprocess.PIPE).stdout)
host_hashes = self._extract_hashes_from_md5sum_output(
self._port.host.executive.popen(args=['%s_host' % self._md5sum_path, host_file],
stdout=subprocess.PIPE).stdout)
if host_hashes and device_hashes == host_hashes:
return
- self._push_to_device(host_file, device_file)
+
+ self._android_commands.push(host_file, device_file)
def _push_executable(self):
- self._push_file_if_needed(self._port.path_to_forwarder(), DEVICE_FORWARDER_PATH)
- self._push_file_if_needed(self._port._build_path('DumpRenderTree.pak'), DEVICE_DRT_DIR + 'DumpRenderTree.pak')
- self._push_file_if_needed(self._port._build_path('DumpRenderTree_resources'), DEVICE_DRT_DIR + 'DumpRenderTree_resources')
- self._push_file_if_needed(self._port._build_path('android_main_fonts.xml'), DEVICE_DRT_DIR + 'android_main_fonts.xml')
- self._push_file_if_needed(self._port._build_path('android_fallback_fonts.xml'), DEVICE_DRT_DIR + 'android_fallback_fonts.xml')
- self._run_adb_command(['uninstall', DRT_APP_PACKAGE])
- drt_host_path = self._port._path_to_driver()
- install_result = self._run_adb_command(['install', drt_host_path])
+ self._push_file_if_needed(self._port.path_to_forwarder(), self._driver_details.device_forwarder_path())
+ for resource in self._driver_details.additional_resources():
+ self._push_file_if_needed(self._port._build_path(resource), self._driver_details.device_directory() + resource)
+
+ self._push_file_if_needed(self._port._build_path('android_main_fonts.xml'), self._driver_details.device_directory() + 'android_main_fonts.xml')
+ self._push_file_if_needed(self._port._build_path('android_fallback_fonts.xml'), self._driver_details.device_directory() + 'android_fallback_fonts.xml')
+
+ self._android_commands.run(['uninstall', self._driver_details.package_name()])
+ driver_host_path = self._port._path_to_driver()
+ install_result = self._android_commands.run(['install', driver_host_path])
if install_result.find('Success') == -1:
- self._abort('Failed to install %s onto device: %s' % (drt_host_path, install_result))
+ self._abort('Failed to install %s onto device: %s' % (driver_host_path, install_result))
def _push_fonts(self):
self._log_debug('Pushing fonts')
path_to_ahem_font = self._port._build_path('AHEM____.TTF')
- self._push_file_if_needed(path_to_ahem_font, DEVICE_FONTS_DIR + 'AHEM____.TTF')
+ self._push_file_if_needed(path_to_ahem_font, self._driver_details.device_fonts_directory() + 'AHEM____.TTF')
for (host_dirs, font_file, package) in HOST_FONT_FILES:
for host_dir in host_dirs:
host_font_path = host_dir + font_file
if self._port._check_file_exists(host_font_path, '', logging=False):
- self._push_file_if_needed(host_font_path, DEVICE_FONTS_DIR + font_file)
+ self._push_file_if_needed(host_font_path, self._driver_details.device_fonts_directory() + font_file)
def _push_test_resources(self):
self._log_debug('Pushing test resources')
@@ -655,47 +773,14 @@
def _push_platform_resources(self):
self._log_debug('Pushing platform resources')
- external_storage = self._port._filesystem.join(self._run_adb_command(['shell', 'echo $EXTERNAL_STORAGE']).strip(), 'Source', 'WebKit', 'chromium')
+ external_storage = self._port._filesystem.join(self._android_commands.run(['shell', 'echo $EXTERNAL_STORAGE']).strip(), 'Source', 'WebKit', 'chromium')
for resource in WEBKIT_PLATFORM_RESOURCES_TO_PUSH:
self._push_file_if_needed(self._port._chromium_base_dir(self._port._filesystem) + '/' + resource, external_storage + '/' + resource)
- def _restart_adb_as_root(self):
- output = self._run_adb_command(['root'])
- if 'adbd is already running as root' in output:
- return
- elif not 'restarting adbd as root' in output:
- self._log_error('Unrecognized output from adb root: %s' % output)
-
- # Regardless the output, give the device a moment to come back online.
- self._run_adb_command(['wait-for-device'])
-
- def _run_adb_command(self, cmd, ignore_error=False):
- self._log_debug('Run adb command: ' + str(cmd))
- if ignore_error:
- error_handler = self._port._executive.ignore_error
- else:
- error_handler = None
- result = self._port._executive.run_command(self._adb_command() + cmd, error_handler=error_handler)
- # Limit the length to avoid too verbose output of commands like 'adb logcat' and 'cat /data/tombstones/tombstone01'
- # whose outputs are normally printed in later logs.
- self._log_debug('Run adb result: ' + result[:80])
- return result
-
- def _link_device_file(self, from_file, to_file, ignore_error=False):
- # rm to_file first to make sure that ln succeeds.
- self._run_adb_command(['shell', 'rm', to_file], ignore_error)
- return self._run_adb_command(['shell', 'ln', '-s', from_file, to_file], ignore_error)
-
- def _push_to_device(self, host_path, device_path, ignore_error=False):
- return self._run_adb_command(['push', host_path, device_path], ignore_error)
-
- def _pull_from_device(self, device_path, host_path, ignore_error=False):
- return self._run_adb_command(['pull', device_path, host_path], ignore_error)
-
def _get_last_stacktrace(self):
- tombstones = self._run_adb_command(['shell', 'ls', '-n', '/data/tombstones'])
+ tombstones = self._android_commands.run(['shell', 'ls', '-n', '/data/tombstones'])
if not tombstones or tombstones.startswith('/data/tombstones: No such file or directory'):
- self._log_error('DRT crashed, but no tombstone found!')
+ self._log_error('The driver crashed, but no tombstone found!')
return ''
tombstones = tombstones.rstrip().split('\n')
last_tombstone = tombstones[0].split()
@@ -714,45 +799,41 @@
# stack trace into a human readable format, if needed.
# It takes a long time, so don't do it here.
return '%s\n%s' % (' '.join(last_tombstone),
- self._run_adb_command(['shell', 'cat', '/data/tombstones/' + last_tombstone[6]]))
+ self._android_commands.run(['shell', 'cat', '/data/tombstones/' + last_tombstone[6]]))
def _get_logcat(self):
- return self._run_adb_command(['logcat', '-d', '-v', 'threadtime'])
+ return self._android_commands.run(['logcat', '-d', '-v', 'threadtime'])
def _setup_performance(self):
# Disable CPU scaling and drop ram cache to reduce noise in tests
if not self._original_governors:
- governor_files = self._run_adb_command(['shell', 'ls', SCALING_GOVERNORS_PATTERN])
+ governor_files = self._android_commands.run(['shell', 'ls', SCALING_GOVERNORS_PATTERN])
if governor_files.find('No such file or directory') == -1:
for file in governor_files.split():
- self._original_governors[file] = self._run_adb_command(['shell', 'cat', file]).strip()
- self._run_adb_command(['shell', 'echo', 'performance', '>', file])
+ self._original_governors[file] = self._android_commands.run(['shell', 'cat', file]).strip()
+ self._android_commands.run(['shell', 'echo', 'performance', '>', file])
def _teardown_performance(self):
for file, original_content in self._original_governors.items():
- self._run_adb_command(['shell', 'echo', original_content, '>', file])
+ self._android_commands.run(['shell', 'echo', original_content, '>', file])
self._original_governors = {}
def _get_crash_log(self, stdout, stderr, newer_than):
if not stdout:
stdout = ''
- stdout += '********* [%s] Logcat:\n%s' % (self._device_serial, self._get_logcat())
+ stdout += '********* [%s] Logcat:\n%s' % (self._android_commands.get_serial(), self._get_logcat())
if not stderr:
stderr = ''
- stderr += '********* [%s] Tombstone file:\n%s' % (self._device_serial, self._get_last_stacktrace())
+ stderr += '********* [%s] Tombstone file:\n%s' % (self._android_commands.get_serial(), self._get_last_stacktrace())
return super(ChromiumAndroidDriver, self)._get_crash_log(stdout, stderr, newer_than)
def cmd_line(self, pixel_tests, per_test_args):
# The returned command line is used to start _server_process. In our case, it's an interactive 'adb shell'.
- # The command line passed to the DRT process is returned by _drt_cmd_line() instead.
- return self._adb_command() + ['shell']
+ # The command line passed to the driver process is returned by _driver_cmd_line() instead.
+ return self._android_commands.adb_command() + ['shell']
- def _file_exists_on_device(self, full_file_path):
- assert full_file_path.startswith('/')
- return self._run_adb_command(['shell', 'ls', full_file_path]).strip() == full_file_path
-
- def _drt_cmd_line(self, pixel_tests, per_test_args):
- return driver.Driver.cmd_line(self, pixel_tests, per_test_args) + ['--create-stdin-fifo', '--separate-stderr-fifo']
+ def _android_driver_cmd_line(self, pixel_tests, per_test_args):
+ return driver.Driver.cmd_line(self, pixel_tests, per_test_args) + self._driver_details.additional_command_line_flags()
@staticmethod
def _loop_with_timeout(condition, timeout_secs):
@@ -763,17 +844,17 @@
return False
def _all_pipes_created(self):
- return (self._file_exists_on_device(self._in_fifo_path) and
- self._file_exists_on_device(self._out_fifo_path) and
- self._file_exists_on_device(self._err_fifo_path))
+ return (self._android_commands.file_exists(self._in_fifo_path) and
+ self._android_commands.file_exists(self._out_fifo_path) and
+ self._android_commands.file_exists(self._err_fifo_path))
def _remove_all_pipes(self):
for file in [self._in_fifo_path, self._out_fifo_path, self._err_fifo_path]:
- self._run_adb_command(['shell', 'rm', file])
+ self._android_commands.run(['shell', 'rm', file])
- return (not self._file_exists_on_device(self._in_fifo_path) and
- not self._file_exists_on_device(self._out_fifo_path) and
- not self._file_exists_on_device(self._err_fifo_path))
+ return (not self._android_commands.file_exists(self._in_fifo_path) and
+ not self._android_commands.file_exists(self._out_fifo_path) and
+ not self._android_commands.file_exists(self._err_fifo_path))
def run_test(self, driver_input, stop_when_done):
base = self._port.lookup_virtual_test_base(driver_input.test_name)
@@ -785,8 +866,8 @@
def start(self, pixel_tests, per_test_args):
# Only one driver instance is allowed because of the nature of Android activity.
- # The single driver needs to restart DumpRenderTree when the command line changes.
- cmd_line = self._drt_cmd_line(pixel_tests, per_test_args)
+ # The single driver needs to restart content_shell when the command line changes.
+ cmd_line = self._android_driver_cmd_line(pixel_tests, per_test_args)
if cmd_line != self._cmd_line:
self.stop()
self._cmd_line = cmd_line
@@ -798,45 +879,45 @@
for retries in range(3):
if self._start_once(pixel_tests, per_test_args):
return
- self._log_error('Failed to start DumpRenderTree application. Retries=%d. Log:%s' % (retries, self._get_logcat()))
+ self._log_error('Failed to start the content_shell application. Retries=%d. Log:%s' % (retries, self._get_logcat()))
self.stop()
time.sleep(2)
- self._abort('Failed to start DumpRenderTree application multiple times. Give up.')
+ self._abort('Failed to start the content_shell application multiple times. Giving up.')
def _start_once(self, pixel_tests, per_test_args):
super(ChromiumAndroidDriver, self)._start(pixel_tests, per_test_args)
self._log_debug('Starting forwarder')
self._forwarder_process = self._port._server_process_constructor(
- self._port, 'Forwarder', self._adb_command() + ['shell', '%s -D %s' % (DEVICE_FORWARDER_PATH, FORWARD_PORTS)])
+ self._port, 'Forwarder', self._android_commands.adb_command() + ['shell', '%s -D %s' % (self._driver_details.device_forwarder_path(), FORWARD_PORTS)])
self._forwarder_process.start()
- self._run_adb_command(['logcat', '-c'])
- self._run_adb_command(['shell', 'echo'] + self._cmd_line + ['>', COMMAND_LINE_FILE])
- start_result = self._run_adb_command(['shell', 'am', 'start', '-e', 'RunInSubThread', '-n', DRT_ACTIVITY_FULL_NAME])
+ self._android_commands.run(['logcat', '-c'])
+ self._android_commands.run(['shell', 'echo'] + self._cmd_line + ['>', self._driver_details.command_line_file()])
+ start_result = self._android_commands.run(['shell', 'am', 'start', '-e', 'RunInSubThread', '-n', self._driver_details.activity_name()])
if start_result.find('Exception') != -1:
- self._log_error('Failed to start DumpRenderTree application. Exception:\n' + start_result)
+ self._log_error('Failed to start the content_shell application. Exception:\n' + start_result)
return False
- if not ChromiumAndroidDriver._loop_with_timeout(self._all_pipes_created, DRT_START_STOP_TIMEOUT_SECS):
+ if not ChromiumAndroidDriver._loop_with_timeout(self._all_pipes_created, DRIVER_START_STOP_TIMEOUT_SECS):
return False
# Read back the shell prompt to ensure adb shell ready.
- deadline = time.time() + DRT_START_STOP_TIMEOUT_SECS
+ deadline = time.time() + DRIVER_START_STOP_TIMEOUT_SECS
self._server_process.start()
self._read_prompt(deadline)
self._log_debug('Interactive shell started')
- # Start a process to read from the stdout fifo of the DumpRenderTree app and print to stdout.
+ # Start a process to read from the stdout fifo of the test driver and print to stdout.
self._log_debug('Redirecting stdout to ' + self._out_fifo_path)
self._read_stdout_process = self._port._server_process_constructor(
- self._port, 'ReadStdout', self._adb_command() + ['shell', 'cat', self._out_fifo_path])
+ self._port, 'ReadStdout', self._android_commands.adb_command() + ['shell', 'cat', self._out_fifo_path])
self._read_stdout_process.start()
- # Start a process to read from the stderr fifo of the DumpRenderTree app and print to stdout.
+ # Start a process to read from the stderr fifo of the test driver and print to stdout.
self._log_debug('Redirecting stderr to ' + self._err_fifo_path)
self._read_stderr_process = self._port._server_process_constructor(
- self._port, 'ReadStderr', self._adb_command() + ['shell', 'cat', self._err_fifo_path])
+ self._port, 'ReadStderr', self._android_commands.adb_command() + ['shell', 'cat', self._err_fifo_path])
self._read_stderr_process.start()
self._log_debug('Redirecting stdin to ' + self._in_fifo_path)
@@ -846,7 +927,7 @@
self._server_process.replace_outputs(self._read_stdout_process._proc.stdout, self._read_stderr_process._proc.stdout)
def deadlock_detector(processes, normal_startup_event):
- if not ChromiumAndroidDriver._loop_with_timeout(lambda: normal_startup_event.is_set(), DRT_START_STOP_TIMEOUT_SECS):
+ if not ChromiumAndroidDriver._loop_with_timeout(lambda: normal_startup_event.is_set(), DRIVER_START_STOP_TIMEOUT_SECS):
# If normal_startup_event is not set in time, the main thread must be blocked at
# reading/writing the fifo. Kill the fifo reading/writing processes to let the
# main thread escape from the deadlocked state. After that, the main thread will
@@ -867,9 +948,9 @@
line = self._server_process.read_stdout_line(deadline)
if self._server_process.timed_out and not self.has_crashed():
- # DumpRenderTree crashes during startup, or when the deadlock detector detected
- # deadlock and killed the fifo reading/writing processes.
- _log.error('Failed to start DumpRenderTree: \n%s' % output)
+ # The test driver crashed during startup, or when the deadlock detector hit
+ # a deadlock and killed the fifo reading/writing processes.
+ _log.error('Failed to start the test driver: \n%s' % output)
return False
# Inform the deadlock detector that the startup is successful without deadlock.
@@ -880,17 +961,17 @@
# ps output seems to be fixed width, we only care about the name and the pid
# u0_a72 21630 125 947920 59364 ffffffff 400beee4 S org.chromium.native_test
for line in ps_output.split('\n'):
- if line.find(DRT_APP_PACKAGE) != -1:
+ if line.find(self._driver_details.package_name()) != -1:
match = re.match(r'\S+\s+(\d+)', line)
return int(match.group(1))
def _pid_on_target(self):
# FIXME: There must be a better way to do this than grepping ps output!
- ps_output = self._run_adb_command(['shell', 'ps'])
- return self._pid_from_android_ps_output(ps_output, DRT_APP_PACKAGE)
+ ps_output = self._android_commands.run(['shell', 'ps'])
+ return self._pid_from_android_ps_output(ps_output, self._driver_details.package_name())
def stop(self):
- self._run_adb_command(['shell', 'am', 'force-stop', DRT_APP_PACKAGE])
+ self._android_commands.run(['shell', 'am', 'force-stop', self._driver_details.package_name()])
if self._read_stdout_process:
self._read_stdout_process.kill()
@@ -907,7 +988,7 @@
self._forwarder_process = None
if self._has_setup:
- if not ChromiumAndroidDriver._loop_with_timeout(self._remove_all_pipes, DRT_START_STOP_TIMEOUT_SECS):
+ if not ChromiumAndroidDriver._loop_with_timeout(self._remove_all_pipes, DRIVER_START_STOP_TIMEOUT_SECS):
raise AssertionError('Failed to remove fifo files. May be locked.')
def _command_from_driver_input(self, driver_input):
@@ -927,8 +1008,3 @@
if last_char in ('#', '$'):
return
last_char = current_char
-
- def _adb_command(self):
- if not self._adb_command_base:
- self._adb_command_base = [self._port.path_to_adb(), '-s', self._device_serial]
- return self._adb_command_base
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_android_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_android_unittest.py
index f34bbcd..62995b1 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_android_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_android_unittest.py
@@ -42,71 +42,100 @@
from webkitpy.layout_tests.port import driver_unittest
from webkitpy.tool.mocktool import MockOptions
+# Any "adb" commands will be interpret by this class instead of executing actual
+# commansd on the file system, which we don't want to do.
+class MockAndroidDebugBridge:
+ def __init__(self, device_count):
+ self._device_count = device_count
+ self._last_command = None
-class MockRunCommand(object):
- def __init__(self):
- self._mock_logcat = ''
- self._mock_devices_output = ''
- self._mock_devices = []
- self._mock_ls_tombstones = ''
+ # Local public methods.
- def mock_run_command_fn(self, args):
- if not args[0].endswith('adb'):
- return ''
- if args[1] == 'devices':
- return self._mock_devices_output
- if args[1] == 'version':
+ def run_command(self, args):
+ self._last_command = ' '.join(args)
+ if args[0].startswith('path'):
+ if args[0] == 'path1':
+ return ''
+ if args[0] == 'path2':
+ return 'version 1.1'
+
return 'version 1.0'
- assert len(args) > 3
- assert args[1] == '-s'
- assert args[2] in self._mock_devices
- if args[3] == 'shell':
- if args[4:] == ['ls', '-n', '/data/tombstones']:
- return self._mock_ls_tombstones
- elif args[4] == 'cat':
- return args[5] + '\nmock_contents\n'
- elif args[3] == 'logcat':
- return self._mock_logcat
+ if args[0] == 'adb':
+ if len(args) > 1 and args[1] == 'version':
+ return 'version 1.0'
+ if len(args) > 1 and args[1] == 'devices':
+ return self._get_device_output()
+ if len(args) > 3 and args[3] == 'command':
+ return 'mockoutput'
+
return ''
- def mock_no_device(self):
- self._mock_devices = []
- self._mock_devices_output = 'List of devices attached'
+ def last_command(self):
+ return self._last_command
- def mock_one_device(self):
- self._mock_devices = ['123456789ABCDEF0']
- self._mock_devices_output = ('List of devices attached\n'
- '%s\tdevice\n' % self._mock_devices[0])
+ # Local private methods.
- def mock_two_devices(self):
- self._mock_devices = ['123456789ABCDEF0', '23456789ABCDEF01']
- self._mock_devices_output = ('* daemon not running. starting it now on port 5037 *'
- '* daemon started successfully *'
- 'List of devices attached\n'
- '%s\tdevice\n'
- '%s\tdevice\n' % (self._mock_devices[0], self._mock_devices[1]))
+ def _get_device_output(self):
+ serials = ['123456789ABCDEF0', '123456789ABCDEF1', '123456789ABCDEF2',
+ '123456789ABCDEF3', '123456789ABCDEF4', '123456789ABCDEF5']
+ output = 'List of devices attached\n'
+ for serial in serials[:self._device_count]:
+ output += '%s\tdevice\n' % serial
+ return output
- def mock_no_tombstone_dir(self):
- self._mock_ls_tombstones = '/data/tombstones: No such file or directory'
- def mock_no_tombstone_file(self):
- self._mock_ls_tombstones = ''
+class AndroidCommandsTest(unittest.TestCase):
+ def setUp(self):
+ chromium_android.AndroidCommands._adb_command_path = None
+ chromium_android.AndroidCommands._adb_command_path_options = ['adb']
- def mock_ten_tombstones(self):
- self._mock_ls_tombstones = ('-rw------- 1000 1000 218643 2012-04-26 18:15 tombstone_00\n'
- '-rw------- 1000 1000 241695 2012-04-26 18:15 tombstone_01\n'
- '-rw------- 1000 1000 219472 2012-04-26 18:16 tombstone_02\n'
- '-rw------- 1000 1000 45316 2012-04-27 16:33 tombstone_03\n'
- '-rw------- 1000 1000 82022 2012-04-23 16:57 tombstone_04\n'
- '-rw------- 1000 1000 82015 2012-04-23 16:57 tombstone_05\n'
- '-rw------- 1000 1000 81974 2012-04-23 16:58 tombstone_06\n'
- '-rw------- 1000 1000 237409 2012-04-26 17:41 tombstone_07\n'
- '-rw------- 1000 1000 276089 2012-04-26 18:15 tombstone_08\n'
- '-rw------- 1000 1000 219618 2012-04-26 18:15 tombstone_09\n')
+ def make_executive(self, device_count):
+ self._mock_executive = MockAndroidDebugBridge(device_count)
+ return MockExecutive2(run_command_fn=self._mock_executive.run_command)
- def mock_logcat(self, content):
- self._mock_logcat = content
+ def make_android_commands(self, device_count, serial):
+ return chromium_android.AndroidCommands(self.make_executive(device_count), serial)
+
+ # The "adb" binary with the latest version should be used.
+ def serial_test_adb_command_path(self):
+ executive = self.make_executive(0)
+
+ chromium_android.AndroidCommands.set_adb_command_path_options(['path1', 'path2', 'path3'])
+ self.assertEqual('path2', chromium_android.AndroidCommands.adb_command_path(executive))
+
+ # The get_devices() method should throw if there aren't any devices. Otherwise it returns an array.
+ def test_get_devices(self):
+ self.assertRaises(AssertionError, chromium_android.AndroidCommands.get_devices, self.make_executive(0))
+ self.assertEquals(1, len(chromium_android.AndroidCommands.get_devices(self.make_executive(1))))
+ self.assertEquals(5, len(chromium_android.AndroidCommands.get_devices(self.make_executive(5))))
+
+ # The used adb command should include the device's serial number, and get_serial() should reflect this.
+ def test_adb_command_and_get_serial(self):
+ android_commands = self.make_android_commands(1, '123456789ABCDEF0')
+ self.assertEquals(['adb', '-s', '123456789ABCDEF0'], android_commands.adb_command())
+ self.assertEquals('123456789ABCDEF0', android_commands.get_serial())
+
+ # Running an adb command should return the command's output.
+ def test_run_command(self):
+ android_commands = self.make_android_commands(1, '123456789ABCDEF0')
+
+ output = android_commands.run(['command'])
+ self.assertEquals('adb -s 123456789ABCDEF0 command', self._mock_executive.last_command())
+ self.assertEquals('mockoutput', output)
+
+ # Test that the convenience methods create the expected commands.
+ def test_convenience_methods(self):
+ android_commands = self.make_android_commands(1, '123456789ABCDEF0')
+
+ android_commands.file_exists('/tombstones')
+ self.assertEquals('adb -s 123456789ABCDEF0 shell ls /tombstones', self._mock_executive.last_command())
+
+ android_commands.push('foo', 'bar')
+ self.assertEquals('adb -s 123456789ABCDEF0 push foo bar', self._mock_executive.last_command())
+
+ android_commands.pull('bar', 'foo')
+ self.assertEquals('adb -s 123456789ABCDEF0 pull bar foo', self._mock_executive.last_command())
class ChromiumAndroidPortTest(chromium_port_testcase.ChromiumPortTestCase):
@@ -115,232 +144,126 @@
def make_port(self, **kwargs):
port = super(ChromiumAndroidPortTest, self).make_port(**kwargs)
- self.mock_run_command = MockRunCommand()
- self.mock_run_command.mock_one_device()
- port._executive = MockExecutive2(run_command_fn=self.mock_run_command.mock_run_command_fn)
+ port._mock_adb = MockAndroidDebugBridge(kwargs.get('device_count', 1))
+ port._executive = MockExecutive2(run_command_fn=port._mock_adb.run_command)
return port
- def test_attributes(self):
- port = self.make_port()
- self.assertEqual(port.baseline_path(), port._webkit_baseline_path('chromium-android'))
+ # Test that the right driver details will be set for DumpRenderTree vs. content_shell
+ def test_driver_details(self):
+ port_dump_render_tree = self.make_port()
+ port_content_shell = self.make_port(options=optparse.Values({'driver_name': 'content_shell'}))
+ self.assertIsInstance(port_dump_render_tree._driver_details, chromium_android.DumpRenderTreeDriverDetails)
+ self.assertIsInstance(port_content_shell._driver_details, chromium_android.ContentShellDriverDetails)
+
+ # Test that the number of child processes to create depends on the devices.
+ def test_default_child_processes(self):
+ port_default = self.make_port(device_count=5)
+ port_fixed_device = self.make_port(device_count=5, options=optparse.Values({'adb_device': '123456789ABCDEF9'}))
+
+ self.assertEquals(5, port_default.default_child_processes())
+ self.assertEquals(1, port_fixed_device.default_child_processes())
+
+ # Test that an HTTP server indeed is required by Android (as we serve all tests over them)
+ def test_requires_http_server(self):
+ self.assertTrue(self.make_port(device_count=1).requires_http_server())
+
+ # Disable this test because Android introduces its own TestExpectations file.
+ def test_expectations_files(self):
+ pass
+
+ # Test that Chromium Android still uses a port-specific TestExpectations file.
+ def test_uses_android_specific_test_expectations(self):
+ port = self.make_port()
+
+ android_count = len(port._port_specific_expectations_files())
+ chromium_count = len(super(chromium_android.ChromiumAndroidPort, port)._port_specific_expectations_files())
+
+ self.assertEquals(android_count - 1, chromium_count)
+
+ # Tests the default timeouts for Android, which are different than the rest of Chromium.
def test_default_timeout_ms(self):
self.assertEqual(self.make_port(options=optparse.Values({'configuration': 'Release'})).default_timeout_ms(), 10000)
self.assertEqual(self.make_port(options=optparse.Values({'configuration': 'Debug'})).default_timeout_ms(), 10000)
- def test_expectations_files(self):
- # FIXME: override this test temporarily while we're still upstreaming the android port and
- # using a custom expectations file.
- pass
-
- def test_get_devices_no_device(self):
- port = self.make_port()
- self.mock_run_command.mock_no_device()
- self.assertRaises(AssertionError, port._get_devices)
-
- def test_get_devices_one_device(self):
- port = self.make_port()
- self.mock_run_command.mock_one_device()
- self.assertEqual(self.mock_run_command._mock_devices, port._get_devices())
- self.assertEqual(1, port.default_child_processes())
-
- def test_get_devices_two_devices(self):
- port = self.make_port()
- self.mock_run_command.mock_two_devices()
- self.assertEqual(self.mock_run_command._mock_devices, port._get_devices())
- self.assertEqual(2, port.default_child_processes())
-
- def test_get_device_serial_no_device(self):
- port = self.make_port()
- self.mock_run_command.mock_no_device()
- self.assertRaises(AssertionError, port._get_device_serial, 0)
-
- def test_get_device_serial_one_device(self):
- port = self.make_port()
- self.mock_run_command.mock_one_device()
- self.assertEqual(self.mock_run_command._mock_devices[0], port._get_device_serial(0))
- self.assertRaises(AssertionError, port._get_device_serial, 1)
-
- def test_get_device_serial_two_devices(self):
- port = self.make_port()
- self.mock_run_command.mock_two_devices()
- self.assertEqual(self.mock_run_command._mock_devices[0], port._get_device_serial(0))
- self.assertEqual(self.mock_run_command._mock_devices[1], port._get_device_serial(1))
- self.assertRaises(AssertionError, port._get_device_serial, 2)
-
- def test_must_require_http_server(self):
- port = self.make_port()
- self.assertEqual(port.requires_http_server(), True)
-
class ChromiumAndroidDriverTest(unittest.TestCase):
def setUp(self):
- self.mock_run_command = MockRunCommand()
- self.mock_run_command.mock_one_device()
- self.port = chromium_android.ChromiumAndroidPort(
- MockSystemHost(executive=MockExecutive2(run_command_fn=self.mock_run_command.mock_run_command_fn)),
- 'chromium-android')
- self.driver = chromium_android.ChromiumAndroidDriver(self.port, worker_number=0, pixel_tests=True)
+ self._mock_adb = MockAndroidDebugBridge(1)
+ self._mock_executive = MockExecutive2(run_command_fn=self._mock_adb.run_command)
+ self._port = chromium_android.ChromiumAndroidPort(MockSystemHost(executive=self._mock_executive), 'chromium-android')
+ self._driver = chromium_android.ChromiumAndroidDriver(self._port, worker_number=0,
+ pixel_tests=True, driver_details=chromium_android.ContentShellDriverDetails())
- def test_get_last_stacktrace(self):
- self.mock_run_command.mock_no_tombstone_dir()
- self.assertEqual(self.driver._get_last_stacktrace(), '')
-
- self.mock_run_command.mock_no_tombstone_file()
- self.assertEqual(self.driver._get_last_stacktrace(), '')
-
- self.mock_run_command.mock_ten_tombstones()
- self.assertEqual(self.driver._get_last_stacktrace(),
- '-rw------- 1000 1000 45316 2012-04-27 16:33 tombstone_03\n'
- '/data/tombstones/tombstone_03\nmock_contents\n')
-
- def test_get_crash_log(self):
- self.mock_run_command.mock_logcat('logcat contents\n')
- self.mock_run_command.mock_ten_tombstones()
- self.driver._crashed_process_name = 'foo'
- self.driver._crashed_pid = 1234
- self.assertEqual(self.driver._get_crash_log('out bar\nout baz\n', 'err bar\nerr baz\n', newer_than=None),
- ('err bar\n'
- 'err baz\n'
- '********* [123456789ABCDEF0] Tombstone file:\n'
- '-rw------- 1000 1000 45316 2012-04-27 16:33 tombstone_03\n'
- '/data/tombstones/tombstone_03\n'
- 'mock_contents\n',
- u'crash log for foo (pid 1234):\n'
- u'STDOUT: out bar\n'
- u'STDOUT: out baz\n'
- u'STDOUT: ********* [123456789ABCDEF0] Logcat:\n'
- u'STDOUT: logcat contents\n'
- u'STDERR: err bar\n'
- u'STDERR: err baz\n'
- u'STDERR: ********* [123456789ABCDEF0] Tombstone file:\n'
- u'STDERR: -rw------- 1000 1000 45316 2012-04-27 16:33 tombstone_03\n'
- u'STDERR: /data/tombstones/tombstone_03\n'
- u'STDERR: mock_contents\n'))
-
- self.driver._crashed_process_name = None
- self.driver._crashed_pid = None
- self.assertEqual(self.driver._get_crash_log(None, None, newer_than=None),
- ('********* [123456789ABCDEF0] Tombstone file:\n'
- '-rw------- 1000 1000 45316 2012-04-27 16:33 tombstone_03\n'
- '/data/tombstones/tombstone_03\n'
- 'mock_contents\n',
- u'crash log for <unknown process name> (pid <unknown>):\n'
- u'STDOUT: ********* [123456789ABCDEF0] Logcat:\n'
- u'STDOUT: logcat contents\n'
- u'STDERR: ********* [123456789ABCDEF0] Tombstone file:\n'
- u'STDERR: -rw------- 1000 1000 45316 2012-04-27 16:33 tombstone_03\n'
- u'STDERR: /data/tombstones/tombstone_03\n'
- u'STDERR: mock_contents\n'))
-
+ # The cmd_line() method in the Android port is used for starting a shell, not the test runner.
def test_cmd_line(self):
- cmd_line = self.driver.cmd_line(True, ['anything'])
- self.assertEqual(['adb', '-s', self.mock_run_command._mock_devices[0], 'shell'], cmd_line)
+ self.assertEquals(['adb', '-s', '123456789ABCDEF0', 'shell'], self._driver.cmd_line(False, []))
- def test_drt_cmd_line(self):
- cmd_line = self.driver._drt_cmd_line(True, ['--a'])
- self.assertIn('--a', cmd_line)
- self.assertIn('--create-stdin-fifo', cmd_line)
- self.assertIn('--separate-stderr-fifo', cmd_line)
-
+ # Test that the Chromium Android port can interpret Android's shell output.
def test_read_prompt(self):
- self.driver._server_process = driver_unittest.MockServerProcess(lines=['root@android:/ # '])
- self.assertIsNone(self.driver._read_prompt(time.time() + 1))
- self.driver._server_process = driver_unittest.MockServerProcess(lines=['$ '])
- self.assertIsNone(self.driver._read_prompt(time.time() + 1))
-
- def test_command_from_driver_input(self):
- driver_input = driver.DriverInput('foo/bar/test.html', 10, 'checksum', True)
- expected_command = "/data/local/tmp/third_party/WebKit/LayoutTests/foo/bar/test.html'--pixel-test'checksum\n"
- if (sys.platform != "cygwin"):
- self.assertEqual(self.driver._command_from_driver_input(driver_input), expected_command)
-
- driver_input = driver.DriverInput('http/tests/foo/bar/test.html', 10, 'checksum', True)
- expected_command = "http://127.0.0.1:8000/foo/bar/test.html'--pixel-test'checksum\n"
- self.assertEqual(self.driver._command_from_driver_input(driver_input), expected_command)
-
- def test_pid_from_android_ps_output(self):
- # FIXME: Use a larger blob of ps output.
- ps_output = """u0_a72 21630 125 947920 59364 ffffffff 400beee4 S org.chromium.native_test"""
- pid = self.driver._pid_from_android_ps_output(ps_output, "org.chromium.native_test")
- self.assertEqual(pid, 21630)
+ self._driver._server_process = driver_unittest.MockServerProcess(lines=['root@android:/ # '])
+ self.assertIsNone(self._driver._read_prompt(time.time() + 1))
+ self._driver._server_process = driver_unittest.MockServerProcess(lines=['$ '])
+ self.assertIsNone(self._driver._read_prompt(time.time() + 1))
-class AndroidPerfTest(unittest.TestCase):
- def test_perf_output_regexp(self):
- perf_output = """[kernel.kallsyms] with build id 5a20f6299bdb955a2f07711bb7f65cd706fe7469 not found, continuing without symbols
-Failed to open /tmp/perf-14168.map, continuing without symbols
-Kernel address maps (/proc/{kallsyms,modules}) were restricted.
-
-Check /proc/sys/kernel/kptr_restrict before running 'perf record'.
-
-As no suitable kallsyms nor vmlinux was found, kernel samples
-can't be resolved.
-
-Samples in kernel modules can't be resolved as well.
-
-# Events: 31K cycles
-#
-# Overhead Command Shared Object
-# ........ ............... ........................... .....................................................................................................................................................................
-#
- 16.18% DumpRenderTree perf-14168.map [.] 0x21270ac0cf43
- 12.72% DumpRenderTree DumpRenderTree [.] v8::internal::JSObject::GetElementWithInterceptor(v8::internal::Object*, unsigned int)
- 8.28% DumpRenderTree DumpRenderTree [.] v8::internal::LoadPropertyWithInterceptorOnly(v8::internal::Arguments, v8::internal::Isolate*)
- 5.60% DumpRenderTree DumpRenderTree [.] WTF::AtomicString WebCore::v8StringToWebCoreString<WTF::AtomicString>(v8::Handle<v8::String>, WebCore::ExternalMode)
- 4.60% DumpRenderTree DumpRenderTree [.] WebCore::WeakReferenceMap<void, v8::Object>::get(void*)
- 3.99% DumpRenderTree DumpRenderTree [.] _ZNK3WTF7HashMapIPNS_16AtomicStringImplEPN7WebCore7ElementENS_7PtrHashIS2_EENS_10HashTraitsIS2_EENS8_IS5_EEE3getERKS2_.isra.98
- 3.69% DumpRenderTree DumpRenderTree [.] WebCore::DocumentV8Internal::getElementByIdCallback(v8::Arguments const&)
- 3.23% DumpRenderTree DumpRenderTree [.] WebCore::V8ParameterBase::prepareBase()
- 2.83% DumpRenderTree DumpRenderTree [.] WTF::AtomicString::add(unsigned short const*, unsigned int)
- 2.73% DumpRenderTree DumpRenderTree [.] WebCore::DocumentV8Internal::getElementsByTagNameCallback(v8::Arguments const&)
- 2.47% DumpRenderTree DumpRenderTree [.] _ZN2v86Object27GetPointerFromInternalFieldEi.constprop.439
- 2.43% DumpRenderTree DumpRenderTree [.] v8::internal::Isolate::SetCurrentVMState(v8::internal::StateTag)
-"""
- expected_first_ten_lines = """ 16.18% DumpRenderTree perf-14168.map [.] 0x21270ac0cf43
- 12.72% DumpRenderTree DumpRenderTree [.] v8::internal::JSObject::GetElementWithInterceptor(v8::internal::Object*, unsigned int)
- 8.28% DumpRenderTree DumpRenderTree [.] v8::internal::LoadPropertyWithInterceptorOnly(v8::internal::Arguments, v8::internal::Isolate*)
- 5.60% DumpRenderTree DumpRenderTree [.] WTF::AtomicString WebCore::v8StringToWebCoreString<WTF::AtomicString>(v8::Handle<v8::String>, WebCore::ExternalMode)
- 4.60% DumpRenderTree DumpRenderTree [.] WebCore::WeakReferenceMap<void, v8::Object>::get(void*)
- 3.99% DumpRenderTree DumpRenderTree [.] _ZNK3WTF7HashMapIPNS_16AtomicStringImplEPN7WebCore7ElementENS_7PtrHashIS2_EENS_10HashTraitsIS2_EENS8_IS5_EEE3getERKS2_.isra.98
- 3.69% DumpRenderTree DumpRenderTree [.] WebCore::DocumentV8Internal::getElementByIdCallback(v8::Arguments const&)
- 3.23% DumpRenderTree DumpRenderTree [.] WebCore::V8ParameterBase::prepareBase()
- 2.83% DumpRenderTree DumpRenderTree [.] WTF::AtomicString::add(unsigned short const*, unsigned int)
- 2.73% DumpRenderTree DumpRenderTree [.] WebCore::DocumentV8Internal::getElementsByTagNameCallback(v8::Arguments const&)
-"""
- host = MockSystemHost()
- profiler = chromium_android.AndroidPerf(host, '/bin/executable', '/tmp/output', 'adb-path', 'device-serial', '/tmp/symfs', '/tmp/kallsyms', 'foo')
- self.assertEqual(profiler._first_ten_lines_of_profile(perf_output), expected_first_ten_lines)
-
-
-class ChromiumAndroidDriverTwoDriversTest(unittest.TestCase):
+class ChromiumAndroidDriverTwoDriverTest(unittest.TestCase):
+ # Test two drivers getting the right serial numbers, and that we disregard per-test arguments.
def test_two_drivers(self):
- mock_run_command = MockRunCommand()
- mock_run_command.mock_two_devices()
- port = chromium_android.ChromiumAndroidPort(
- MockSystemHost(executive=MockExecutive2(run_command_fn=mock_run_command.mock_run_command_fn)),
- 'chromium-android')
- driver0 = chromium_android.ChromiumAndroidDriver(port, worker_number=0, pixel_tests=True)
- driver1 = chromium_android.ChromiumAndroidDriver(port, worker_number=1, pixel_tests=True)
+ mock_adb = MockAndroidDebugBridge(2)
+ mock_executive = MockExecutive2(run_command_fn=mock_adb.run_command)
- cmd_line0 = driver0.cmd_line(True, ['anything'])
- self.assertEqual(['adb', '-s', mock_run_command._mock_devices[0], 'shell'], cmd_line0)
+ port = chromium_android.ChromiumAndroidPort(MockSystemHost(executive=mock_executive), 'chromium-android')
+ driver0 = chromium_android.ChromiumAndroidDriver(port, worker_number=0, pixel_tests=True,
+ driver_details=chromium_android.DumpRenderTreeDriverDetails())
+ driver1 = chromium_android.ChromiumAndroidDriver(port, worker_number=1, pixel_tests=True,
+ driver_details=chromium_android.DumpRenderTreeDriverDetails())
- cmd_line1 = driver1.cmd_line(True, ['anything'])
- self.assertEqual(['adb', '-s', mock_run_command._mock_devices[1], 'shell'], cmd_line1)
+ self.assertEqual(['adb', '-s', '123456789ABCDEF0', 'shell'], driver0.cmd_line(True, []))
+ self.assertEqual(['adb', '-s', '123456789ABCDEF1', 'shell'], driver1.cmd_line(True, ['anything']))
class ChromiumAndroidTwoPortsTest(unittest.TestCase):
+ # Test that the driver's command line indeed goes through to the driver.
def test_options_with_two_ports(self):
- options = MockOptions(additional_drt_flag=['--foo=bar', '--foo=baz'])
- mock_run_command = MockRunCommand()
- mock_run_command.mock_two_devices()
- port0 = chromium_android.ChromiumAndroidPort(
- MockSystemHost(executive=MockExecutive2(run_command_fn=mock_run_command.mock_run_command_fn)),
- 'chromium-android', options=options)
- port1 = chromium_android.ChromiumAndroidPort(
- MockSystemHost(executive=MockExecutive2(run_command_fn=mock_run_command.mock_run_command_fn)),
- 'chromium-android', options=options)
- cmd_line = port1.driver_cmd_line()
- self.assertEqual(cmd_line.count('--encode-binary'), 1)
- self.assertEqual(cmd_line.count('--enable-hardware-gpu'), 1)
+ mock_adb = MockAndroidDebugBridge(2)
+ mock_executive = MockExecutive2(run_command_fn=mock_adb.run_command)
+
+ port0 = chromium_android.ChromiumAndroidPort(MockSystemHost(executive=mock_executive),
+ 'chromium-android', options=MockOptions(additional_drt_flag=['--foo=bar']))
+ port1 = chromium_android.ChromiumAndroidPort(MockSystemHost(executive=mock_executive),
+ 'chromium-android', options=MockOptions(driver_name='content_shell'))
+
+ self.assertEqual(1, port0.driver_cmd_line().count('--foo=bar'))
+ self.assertEqual(0, port1.driver_cmd_line().count('--create-stdin-fifo'))
+
+
+class ChromiumAndroidDriverTwoDriversTest(unittest.TestCase):
+ # Test two drivers getting the right serial numbers, and that we disregard per-test arguments.
+ def test_two_drivers(self):
+ mock_adb = MockAndroidDebugBridge(2)
+ mock_executive = MockExecutive2(run_command_fn=mock_adb.run_command)
+
+ port = chromium_android.ChromiumAndroidPort(MockSystemHost(executive=mock_executive), 'chromium-android')
+ driver0 = chromium_android.ChromiumAndroidDriver(port, worker_number=0, pixel_tests=True,
+ driver_details=chromium_android.ContentShellDriverDetails())
+ driver1 = chromium_android.ChromiumAndroidDriver(port, worker_number=1, pixel_tests=True,
+ driver_details=chromium_android.ContentShellDriverDetails())
+
+ self.assertEqual(['adb', '-s', '123456789ABCDEF0', 'shell'], driver0.cmd_line(True, []))
+ self.assertEqual(['adb', '-s', '123456789ABCDEF1', 'shell'], driver1.cmd_line(True, []))
+
+
+class ChromiumAndroidTwoPortsTest(unittest.TestCase):
+ # Test that the driver's command line indeed goes through to the driver.
+ def test_options_with_two_ports(self):
+ mock_adb = MockAndroidDebugBridge(2)
+ mock_executive = MockExecutive2(run_command_fn=mock_adb.run_command)
+
+ port0 = chromium_android.ChromiumAndroidPort(MockSystemHost(executive=mock_executive),
+ 'chromium-android', options=MockOptions(additional_drt_flag=['--foo=bar']))
+ port1 = chromium_android.ChromiumAndroidPort(MockSystemHost(executive=mock_executive),
+ 'chromium-android', options=MockOptions(driver_name='content_shell'))
+
+ self.assertEqual(1, port0.driver_cmd_line().count('--foo=bar'))
+ self.assertEqual(0, port1.driver_cmd_line().count('--create-stdin-fifo'))
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
index 1d88db7..ff4f559 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
@@ -27,9 +27,11 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import logging
+import re
from webkitpy.common.webkit_finder import WebKitFinder
from webkitpy.layout_tests.port import chromium
+from webkitpy.layout_tests.port import chromium_win
from webkitpy.layout_tests.port import config
@@ -39,21 +41,10 @@
class ChromiumLinuxPort(chromium.ChromiumPort):
port_name = 'chromium-linux'
- SUPPORTED_ARCHITECTURES = ('x86', 'x86_64')
+ SUPPORTED_VERSIONS = ('x86', 'x86_64')
- FALLBACK_PATHS = {
- 'x86_64': [
- 'chromium-linux',
- 'chromium-win',
- 'chromium',
- ],
- 'x86': [
- 'chromium-linux-x86',
- 'chromium-linux',
- 'chromium-win',
- 'chromium',
- ],
- }
+ FALLBACK_PATHS = { 'x86_64': [ 'chromium-linux' ] + chromium_win.ChromiumWinPort.latest_platform_fallback_path() }
+ FALLBACK_PATHS['x86'] = ['chromium-linux-x86'] + FALLBACK_PATHS['x86_64']
DEFAULT_BUILD_DIRECTORIES = ('sconsbuild', 'out')
@@ -74,11 +65,11 @@
file_output = ''
if filesystem.exists(driver_path):
# The --dereference flag tells file to follow symlinks
- file_output = executive.run_command(['file', '--dereference', driver_path], return_stderr=True)
+ file_output = executive.run_command(['file', '--brief', '--dereference', driver_path], return_stderr=True)
- if 'ELF 32-bit LSB executable' in file_output:
+ if re.match(r'ELF 32-bit LSB\s+executable', file_output):
return 'x86'
- if 'ELF 64-bit LSB executable' in file_output:
+ if re.match(r'ELF 64-bit LSB\s+executable', file_output):
return 'x86_64'
if file_output:
_log.warning('Could not determine architecture from "file" output: %s' % file_output)
@@ -99,7 +90,7 @@
chromium.ChromiumPort.__init__(self, host, port_name, **kwargs)
(base, arch) = port_name.rsplit('-', 1)
assert base == 'chromium-linux'
- assert arch in self.SUPPORTED_ARCHITECTURES
+ assert arch in self.SUPPORTED_VERSIONS
assert port_name in ('chromium-linux', 'chromium-linux-x86', 'chromium-linux-x86_64')
self._version = 'lucid' # We only support lucid right now.
self._architecture = arch
@@ -148,10 +139,13 @@
return 'wdiff is not installed; please install using "sudo apt-get install wdiff"'
def _path_to_apache(self):
- if self._is_redhat_based():
- return '/usr/sbin/httpd'
- else:
- return '/usr/sbin/apache2'
+ # The Apache binary path can vary depending on OS and distribution
+ # See http://wiki.apache.org/httpd/DistrosDefaultLayout
+ for path in ["/usr/sbin/httpd", "/usr/sbin/apache2"]:
+ if self._filesystem.exists(path):
+ return path
+ _log.error("Could not find apache. Not installed or unknown path.")
+ return None
def _path_to_lighttpd(self):
return "/usr/sbin/lighttpd"
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux_unittest.py
index 308d02f..2af4fd8 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux_unittest.py
@@ -63,7 +63,7 @@
expected_architecture='x86_64')
self.assert_architecture(file_output='ELF 32-bit LSB executable',
expected_architecture='x86')
- self.assert_architecture(file_output='ELF 64-bit LSB executable',
+ self.assert_architecture(file_output='ELF 64-bit LSB executable',
expected_architecture='x86_64')
def test_check_illegal_port_names(self):
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
index 39de529..8085a32 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
@@ -38,33 +38,17 @@
class ChromiumMacPort(chromium.ChromiumPort):
- SUPPORTED_OS_VERSIONS = ('snowleopard', 'lion', 'mountainlion', 'future')
+ SUPPORTED_VERSIONS = ('snowleopard', 'lion', 'mountainlion')
port_name = 'chromium-mac'
- FALLBACK_PATHS = {
- 'snowleopard': [
- 'chromium-mac-snowleopard',
- 'chromium-mac-lion',
- 'chromium-mac',
- 'chromium',
- ],
- 'lion': [
- 'chromium-mac-lion',
- 'chromium-mac',
- 'chromium',
- ],
- 'mountainlion': [
- 'chromium-mac',
- 'chromium',
- ],
- 'future': [
- 'chromium-mac',
- 'chromium',
- ],
- }
+ FALLBACK_PATHS = { 'mountainlion': [ 'chromium-mac' ]}
+ FALLBACK_PATHS['lion'] = ['chromium-mac-lion'] + FALLBACK_PATHS['mountainlion']
+ FALLBACK_PATHS['snowleopard'] = ['chromium-mac-snowleopard'] + FALLBACK_PATHS['lion']
DEFAULT_BUILD_DIRECTORIES = ('xcodebuild', 'out')
+ CONTENT_SHELL_NAME = 'Content Shell'
+
@classmethod
def determine_full_port_name(cls, host, options, port_name):
if port_name.endswith('-mac'):
@@ -74,7 +58,7 @@
def __init__(self, host, port_name, **kwargs):
chromium.ChromiumPort.__init__(self, host, port_name, **kwargs)
self._version = port_name[port_name.index('chromium-mac-') + len('chromium-mac-'):]
- assert self._version in self.SUPPORTED_OS_VERSIONS
+ assert self._version in self.SUPPORTED_VERSIONS
def _modules_to_search_for_symbols(self):
return [self._build_path('ffmpegsumo.so')]
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py
index bf2ff8f..15476f8 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py
@@ -44,7 +44,7 @@
self.assertEqual(expected, port.name())
def test_versions(self):
- self.assertTrue(self.make_port().name() in ('chromium-mac-snowleopard', 'chromium-mac-lion', 'chromium-mac-mountainlion', 'chromium-mac-future'))
+ self.assertTrue(self.make_port().name() in ('chromium-mac-snowleopard', 'chromium-mac-lion', 'chromium-mac-mountainlion'))
self.assert_name(None, 'snowleopard', 'chromium-mac-snowleopard')
self.assert_name('chromium-mac', 'snowleopard', 'chromium-mac-snowleopard')
@@ -53,13 +53,8 @@
self.assert_name(None, 'lion', 'chromium-mac-lion')
self.assert_name(None, 'mountainlion', 'chromium-mac-mountainlion')
- self.assert_name(None, 'future', 'chromium-mac-future')
self.assert_name('chromium-mac', 'lion', 'chromium-mac-lion')
- self.assert_name('chromium-mac-future', 'snowleopard', 'chromium-mac-future')
- self.assert_name('chromium-mac-future', 'lion', 'chromium-mac-future')
- self.assert_name('chromium-mac-future', 'mountainlion', 'chromium-mac-future')
-
self.assertRaises(AssertionError, self.assert_name, None, 'tiger', 'should-raise-assertion-so-this-value-does-not-matter')
def test_baseline_path(self):
@@ -72,9 +67,6 @@
port = self.make_port(port_name='chromium-mac-mountainlion')
self.assertEqual(port.baseline_path(), port._webkit_baseline_path('chromium-mac'))
- port = self.make_port(port_name='chromium-mac-future')
- self.assertEqual(port.baseline_path(), port._webkit_baseline_path('chromium-mac'))
-
def test_operating_system(self):
self.assertEqual('mac', self.make_port().operating_system())
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_port_testcase.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_port_testcase.py
index f151ced..9db9b90 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_port_testcase.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_port_testcase.py
@@ -73,8 +73,6 @@
"""Validate the complete set of configurations this port knows about."""
port = self.make_port()
self.assertEqual(set(port.all_test_configurations()), set([
- TestConfiguration('icecreamsandwich', 'x86', 'debug'),
- TestConfiguration('icecreamsandwich', 'x86', 'release'),
TestConfiguration('snowleopard', 'x86', 'debug'),
TestConfiguration('snowleopard', 'x86', 'release'),
TestConfiguration('lion', 'x86', 'debug'),
@@ -177,24 +175,24 @@
port.port_name = 'chromium'
generic_path = port.path_to_generic_test_expectations_file()
- expectations_path = port.path_to_test_expectations_file()
chromium_overrides_path = port.path_from_chromium_base(
'webkit', 'tools', 'layout_tests', 'test_expectations.txt')
+ never_fix_tests_path = port._filesystem.join(port.layout_tests_dir(), 'NeverFixTests')
skia_overrides_path = port.path_from_chromium_base(
'skia', 'skia_test_expectations.txt')
port._filesystem.write_text_file(skia_overrides_path, 'dummay text')
port._options.builder_name = 'DUMMY_BUILDER_NAME'
- self.assertEqual(port.expectations_files(), [generic_path, expectations_path, skia_overrides_path, chromium_overrides_path])
+ self.assertEqual(port.expectations_files(), [generic_path, skia_overrides_path, never_fix_tests_path, chromium_overrides_path])
port._options.builder_name = 'builder (deps)'
- self.assertEqual(port.expectations_files(), [generic_path, expectations_path, skia_overrides_path, chromium_overrides_path])
+ self.assertEqual(port.expectations_files(), [generic_path, skia_overrides_path, never_fix_tests_path, chromium_overrides_path])
# A builder which does NOT observe the Chromium test_expectations,
# but still observes the Skia test_expectations...
port._options.builder_name = 'builder'
- self.assertEqual(port.expectations_files(), [generic_path, expectations_path, skia_overrides_path])
+ self.assertEqual(port.expectations_files(), [generic_path, skia_overrides_path, never_fix_tests_path])
def test_expectations_ordering(self):
# since we don't implement self.port_name in ChromiumPort.
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py
index 31e10c5..44ee3e8 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py
@@ -43,17 +43,8 @@
# FIXME: Figure out how to unify this with base.TestConfiguration.all_systems()?
SUPPORTED_VERSIONS = ('xp', 'win7')
- FALLBACK_PATHS = {
- 'xp': [
- 'chromium-win-xp',
- 'chromium-win',
- 'chromium',
- ],
- 'win7': [
- 'chromium-win',
- 'chromium',
- ],
- }
+ FALLBACK_PATHS = { 'win7': [ 'chromium-win' ]}
+ FALLBACK_PATHS['xp'] = ['chromium-win-xp'] + FALLBACK_PATHS['win7']
DEFAULT_BUILD_DIRECTORIES = ('build', 'out')
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/config.py b/Tools/Scripts/webkitpy/layout_tests/port/config.py
index 8c89353..85e517f 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/config.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/config.py
@@ -26,9 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Wrapper objects for WebKit-specific utility routines."""
-
-# FIXME: This file needs to be unified with common/config/ports.py .
+# FIXME: Remove this file altogether. It's useless in a Blink checkout.
import logging
@@ -37,22 +35,6 @@
_log = logging.getLogger(__name__)
-#
-# FIXME: This is used to record if we've already hit the filesystem to look
-# for a default configuration. We cache this to speed up the unit tests,
-# but this can be reset with clear_cached_configuration(). This should be
-# replaced with us consistently using MockConfigs() for tests that don't
-# hit the filesystem at all and provide a reliable value.
-#
-_have_determined_configuration = False
-_configuration = "Release"
-
-
-def clear_cached_configuration():
- global _have_determined_configuration, _configuration
- _have_determined_configuration = False
- _configuration = "Release"
-
class Config(object):
_FLAGS_FROM_CONFIGURATIONS = {
@@ -80,16 +62,7 @@
flags.append('--' + self._port_implementation)
if not self._build_directories.get(configuration):
- args = ["perl", self._webkit_finder.path_to_script("webkit-build-directory")] + flags
- output = self._executive.run_command(args, cwd=self._webkit_finder.webkit_base(), return_stderr=False).rstrip()
- parts = output.split("\n")
- self._build_directories[configuration] = parts[0]
-
- if len(parts) == 2:
- default_configuration = parts[1][len(parts[0]):]
- if default_configuration.startswith("/"):
- default_configuration = default_configuration[1:]
- self._build_directories[default_configuration] = parts[1]
+ self._build_directories[configuration] = self._webkit_finder.path_from_webkit_base('out', configuration)
return self._build_directories[configuration]
@@ -97,45 +70,4 @@
return self._FLAGS_FROM_CONFIGURATIONS[configuration]
def default_configuration(self):
- """Returns the default configuration for the user.
-
- Returns the value set by 'set-webkit-configuration', or "Release"
- if that has not been set. This mirrors the logic in webkitdirs.pm."""
- if not self._default_configuration:
- self._default_configuration = self._determine_configuration()
- if not self._default_configuration:
- self._default_configuration = 'Release'
- if self._default_configuration not in self._FLAGS_FROM_CONFIGURATIONS:
- _log.warn("Configuration \"%s\" is not a recognized value.\n" % self._default_configuration)
- _log.warn("Scripts may fail. See 'set-webkit-configuration --help'.")
- return self._default_configuration
-
- def _determine_configuration(self):
- # This mirrors the logic in webkitdirs.pm:determineConfiguration().
- #
- # FIXME: See the comment at the top of the file regarding unit tests
- # and our use of global mutable static variables.
- # FIXME: We should just @memoize this method and then this will only
- # be read once per object lifetime (which should be sufficiently fast).
- global _have_determined_configuration, _configuration
- if not _have_determined_configuration:
- contents = self._read_configuration()
- if not contents:
- contents = "Release"
- if contents == "Deployment":
- contents = "Release"
- if contents == "Development":
- contents = "Debug"
- _configuration = contents
- _have_determined_configuration = True
- return _configuration
-
- def _read_configuration(self):
- try:
- configuration_path = self._filesystem.join(self.build_directory(None), "Configuration")
- if not self._filesystem.exists(configuration_path):
- return None
- except:
- return None
-
- return self._filesystem.read_text_file(configuration_path).rstrip()
+ return 'Release'
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/config_standalone.py b/Tools/Scripts/webkitpy/layout_tests/port/config_standalone.py
deleted file mode 100644
index 274a07b..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/config_standalone.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""FIXME: This script is used by
-config_unittest.test_default_configuration__standalone() to read the
-default configuration to work around any possible caching / reset bugs. See
-https://bugs.webkit.org/show_bug?id=49360 for the motivation. We can remove
-this test when we remove the global configuration cache in config.py."""
-
-import os
-import sys
-
-
-# Ensure that webkitpy is in PYTHONPATH.
-this_dir = os.path.abspath(sys.path[0])
-up = os.path.dirname
-script_dir = up(up(up(this_dir)))
-if script_dir not in sys.path:
- sys.path.append(script_dir)
-
-from webkitpy.common.system import executive
-from webkitpy.common.system import executive_mock
-from webkitpy.common.system import filesystem
-from webkitpy.common.system import filesystem_mock
-
-import config
-
-
-def main(argv=None):
- if not argv:
- argv = sys.argv
-
- if len(argv) == 3 and argv[1] == '--mock':
- e = executive_mock.MockExecutive2(output='foo\nfoo/%s' % argv[2])
- fs = filesystem_mock.MockFileSystem({'foo/Configuration': argv[2]})
- else:
- e = executive.Executive()
- fs = filesystem.FileSystem()
-
- c = config.Config(e, fs)
- print c.default_configuration()
-
-if __name__ == '__main__':
- main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/config_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/config_unittest.py
deleted file mode 100644
index 27c83ee..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/config_unittest.py
+++ /dev/null
@@ -1,158 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import os
-import sys
-import unittest2 as unittest
-
-from webkitpy.common.system.executive import Executive, ScriptError
-from webkitpy.common.system.executive_mock import MockExecutive2
-from webkitpy.common.system.filesystem import FileSystem
-from webkitpy.common.system.filesystem_mock import MockFileSystem
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.common.webkit_finder import WebKitFinder
-
-import config
-
-
-class ConfigTest(unittest.TestCase):
- def setUp(self):
- config.clear_cached_configuration()
-
- def tearDown(self):
- config.clear_cached_configuration()
-
- def make_config(self, output='', files=None, exit_code=0, exception=None, run_command_fn=None, stderr='', port_implementation=None):
- e = MockExecutive2(output=output, exit_code=exit_code, exception=exception, run_command_fn=run_command_fn, stderr=stderr)
- fs = MockFileSystem(files)
- return config.Config(e, fs, port_implementation=port_implementation)
-
- def assert_configuration(self, contents, expected):
- # This tests that a configuration file containing
- # _contents_ ends up being interpreted as _expected_.
- output = 'foo\nfoo/%s' % contents
- c = self.make_config(output, {'foo/Configuration': contents})
- self.assertEqual(c.default_configuration(), expected)
-
- def test_build_directory(self):
- # --top-level
- def mock_webkit_build_directory(arg_list):
- if arg_list == ['--top-level']:
- return '/WebKitBuild/'
- elif arg_list == ['--configuration', '--debug']:
- return '/WebKitBuild/Debug'
- elif arg_list == ['--configuration', '--release']:
- return '/WebKitBuild/Release'
- elif arg_list == []:
- return '/WebKitBuild/\n/WebKitBuild//Debug\n'
- return 'Error'
-
- def mock_run_command(arg_list):
- if 'webkit-build-directory' in arg_list[1]:
- return mock_webkit_build_directory(arg_list[2:])
- return 'Error'
-
- c = self.make_config(run_command_fn=mock_run_command)
- self.assertEqual(c.build_directory(None), '/WebKitBuild/')
-
- # Test again to check caching
- self.assertEqual(c.build_directory(None), '/WebKitBuild/')
-
- # Test other values
- self.assertTrue(c.build_directory('Release').endswith('/Release'))
- self.assertTrue(c.build_directory('Debug').endswith('/Debug'))
- self.assertRaises(KeyError, c.build_directory, 'Unknown')
-
- # Test that stderr output from webkit-build-directory won't mangle the build dir
- c = self.make_config(output='/WebKitBuild/', stderr="mock stderr output from webkit-build-directory")
- self.assertEqual(c.build_directory(None), '/WebKitBuild/')
-
- def test_build_directory_passes_port_implementation(self):
- def mock_run_command(arg_list):
- self.assetEquals('--gtk' in arg_list)
- return '/tmp'
-
- c = self.make_config(run_command_fn=mock_run_command, port_implementation='gtk')
-
- def test_default_configuration__release(self):
- self.assert_configuration('Release', 'Release')
-
- def test_default_configuration__debug(self):
- self.assert_configuration('Debug', 'Debug')
-
- def test_default_configuration__deployment(self):
- self.assert_configuration('Deployment', 'Release')
-
- def test_default_configuration__development(self):
- self.assert_configuration('Development', 'Debug')
-
- def test_default_configuration__notfound(self):
- # This tests what happens if the default configuration file doesn't exist.
- c = self.make_config(output='foo\nfoo/Release', files={'foo/Configuration': None})
- self.assertEqual(c.default_configuration(), "Release")
-
- def test_default_configuration__unknown(self):
- # Ignore the warning about an unknown configuration value.
- oc = OutputCapture()
- oc.capture_output()
- self.assert_configuration('Unknown', 'Unknown')
- oc.restore_output()
-
- def test_default_configuration__standalone(self):
- # FIXME: This test runs a standalone python script to test
- # reading the default configuration to work around any possible
- # caching / reset bugs. See https://bugs.webkit.org/show_bug.cgi?id=49360
- # for the motivation. We can remove this test when we remove the
- # global configuration cache in config.py.
- e = Executive()
- fs = FileSystem()
- c = config.Config(e, fs)
- script = WebKitFinder(fs).path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'layout_tests', 'port', 'config_standalone.py')
-
- # Note: don't use 'Release' here, since that's the normal default.
- expected = 'Debug'
-
- args = [sys.executable, script, '--mock', expected]
- actual = e.run_command(args).rstrip()
- self.assertEqual(actual, expected)
-
- def test_default_configuration__no_perl(self):
- # We need perl to run webkit-build-directory to find out where the
- # default configuration file is. See what happens if perl isn't
- # installed. (We should get the default value, 'Release').
- c = self.make_config(exception=OSError)
- actual = c.default_configuration()
- self.assertEqual(actual, 'Release')
-
- def test_default_configuration__scripterror(self):
- # We run webkit-build-directory to find out where the default
- # configuration file is. See what happens if that script fails.
- # (We should get the default value, 'Release').
- c = self.make_config(exception=ScriptError())
- actual = c.default_configuration()
- self.assertEqual(actual, 'Release')
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/efl.py b/Tools/Scripts/webkitpy/layout_tests/port/efl.py
deleted file mode 100644
index 0896634..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/efl.py
+++ /dev/null
@@ -1,136 +0,0 @@
-# Copyright (C) 2011 ProFUSION Embedded Systems. All rights reserved.
-# Copyright (C) 2011 Samsung Electronics. All rights reserved.
-# Copyright (C) 2012 Intel Corporation
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""WebKit Efl implementation of the Port interface."""
-
-import os
-
-from webkitpy.layout_tests.models.test_configuration import TestConfiguration
-from webkitpy.layout_tests.port.base import Port
-from webkitpy.layout_tests.port.pulseaudio_sanitizer import PulseAudioSanitizer
-from webkitpy.layout_tests.port.xvfbdriver import XvfbDriver
-
-
-class EflPort(Port):
- port_name = 'efl'
-
- def __init__(self, *args, **kwargs):
- super(EflPort, self).__init__(*args, **kwargs)
-
- self._jhbuild_wrapper_path = [self.path_from_webkit_base('Tools', 'jhbuild', 'jhbuild-wrapper'), '--efl', 'run']
-
- self.set_option_default('wrapper', ' '.join(self._jhbuild_wrapper_path))
- self.webprocess_cmd_prefix = self.get_option('webprocess_cmd_prefix')
-
- self._pulseaudio_sanitizer = PulseAudioSanitizer()
-
- def _port_flag_for_scripts(self):
- return "--efl"
-
- def setup_test_run(self):
- super(EflPort, self).setup_test_run()
- self._pulseaudio_sanitizer.unload_pulseaudio_module()
-
- def setup_environ_for_server(self, server_name=None):
- env = super(EflPort, self).setup_environ_for_server(server_name)
-
- # If DISPLAY environment variable is unset in the system
- # e.g. on build bot, remove DISPLAY variable from the dictionary
- if not 'DISPLAY' in os.environ:
- del env['DISPLAY']
-
- env['TEST_RUNNER_INJECTED_BUNDLE_FILENAME'] = self._build_path('lib', 'libTestRunnerInjectedBundle.so')
- env['TEST_RUNNER_PLUGIN_PATH'] = self._build_path('lib')
-
- # Silence GIO warnings about using the "memory" GSettings backend.
- env['GSETTINGS_BACKEND'] = 'memory'
-
- if self.webprocess_cmd_prefix:
- env['WEB_PROCESS_CMD_PREFIX'] = self.webprocess_cmd_prefix
-
- return env
-
- def default_timeout_ms(self):
- # Tests run considerably slower under gdb
- # or valgrind.
- if self.get_option('webprocess_cmd_prefix'):
- return 350 * 1000
- return super(EflPort, self).default_timeout_ms()
-
- def clean_up_test_run(self):
- super(EflPort, self).clean_up_test_run()
- self._pulseaudio_sanitizer.restore_pulseaudio_module()
-
- def _generate_all_test_configurations(self):
- return [TestConfiguration(version=self._version, architecture='x86', build_type=build_type) for build_type in self.ALL_BUILD_TYPES]
-
- def _driver_class(self):
- return XvfbDriver
-
- def _path_to_driver(self):
- return self._build_path('bin', self.driver_name())
-
- def _path_to_image_diff(self):
- return self._build_path('bin', 'ImageDiff')
-
- def _image_diff_command(self, *args, **kwargs):
- return self._jhbuild_wrapper_path + super(EflPort, self)._image_diff_command(*args, **kwargs)
-
- def _path_to_webcore_library(self):
- static_path = self._build_path('lib', 'libwebcore_efl.a')
- dyn_path = self._build_path('lib', 'libwebcore_efl.so')
- return static_path if self._filesystem.exists(static_path) else dyn_path
-
- def _search_paths(self):
- search_paths = []
- if self.get_option('webkit_test_runner'):
- search_paths.append(self.port_name + '-wk2')
- search_paths.append('wk2')
- else:
- search_paths.append(self.port_name + '-wk1')
- search_paths.append(self.port_name)
- return search_paths
-
- def default_baseline_search_path(self):
- return map(self._webkit_baseline_path, self._search_paths())
-
- def _port_specific_expectations_files(self):
- # FIXME: We should be able to use the default algorithm here.
- return list(reversed([self._filesystem.join(self._webkit_baseline_path(p), 'TestExpectations') for p in self._search_paths()]))
-
- def show_results_html_file(self, results_filename):
- # FIXME: We should find a way to share this implmentation with Gtk,
- # or teach run-launcher how to call run-safari and move this down to WebKitPort.
- run_launcher_args = ["file://%s" % results_filename]
- if self.get_option('webkit_test_runner'):
- run_launcher_args.append('-2')
- # FIXME: old-run-webkit-tests also added ["-graphicssystem", "raster", "-style", "windows"]
- # FIXME: old-run-webkit-tests converted results_filename path for cygwin.
- self._run_script("run-launcher", run_launcher_args)
-
- def check_sys_deps(self, needs_http):
- return super(EflPort, self).check_sys_deps(needs_http) and XvfbDriver.check_xvfb(self)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/efl_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/efl_unittest.py
deleted file mode 100644
index 503afda..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/efl_unittest.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (C) 2011 ProFUSION Embedded Systems. All rights reserved.
-# Copyright (C) 2011 Samsung Electronics. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest2 as unittest
-
-from webkitpy.common.system.executive_mock import MockExecutive
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.layout_tests.port.efl import EflPort
-from webkitpy.layout_tests.port.pulseaudio_sanitizer_mock import PulseAudioSanitizerMock
-from webkitpy.layout_tests.port import port_testcase
-
-
-class EflPortTest(port_testcase.PortTestCase):
- port_name = 'efl'
- port_maker = EflPort
-
- # Additionally mocks out the PulseAudioSanitizer methods.
- def make_port(self, host=None, port_name=None, options=None, os_name=None, os_version=None, **kwargs):
- port = super(EflPortTest, self).make_port(host, port_name, options, os_name, os_version, **kwargs)
- port._pulseaudio_sanitizer = PulseAudioSanitizerMock()
- return port
-
- def test_show_results_html_file(self):
- port = self.make_port()
- port._executive = MockExecutive(should_log=True)
- expected_logs = "MOCK run_command: ['Tools/Scripts/run-launcher', '--release', '--efl', 'file://test.html'], cwd=/mock-checkout\n"
- OutputCapture().assert_outputs(self, port.show_results_html_file, ["test.html"], expected_logs=expected_logs)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/factory.py b/Tools/Scripts/webkitpy/layout_tests/port/factory.py
index 902ee22..e83cdd3 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/factory.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/factory.py
@@ -45,15 +45,6 @@
optparse.make_option('--chromium-android', action='store_const', dest='platform',
const=('chromium-android*' if use_globs else 'chromium-android'),
help=('Alias for --platform=chromium-android*' if use_globs else 'Alias for --platform=chromium')),
- optparse.make_option('--efl', action='store_const', dest='platform',
- const=('efl*' if use_globs else 'efl'),
- help=('Alias for --platform=efl*' if use_globs else 'Alias for --platform=efl')),
- optparse.make_option('--gtk', action='store_const', dest='platform',
- const=('gtk*' if use_globs else 'gtk'),
- help=('Alias for --platform=gtk*' if use_globs else 'Alias for --platform=gtk')),
- optparse.make_option('--qt', action='store_const', dest="platform",
- const=('qt*' if use_globs else 'qt'),
- help=('Alias for --platform=qt' if use_globs else 'Alias for --platform=qt')),
]
@@ -75,7 +66,7 @@
configuration = "Debug" if re.search(r"[d|D](ebu|b)g", builder_name) else "Release"
is_webkit2 = builder_name.find("WK2") != -1
builder_name = builder_name
- return optparse.Values({'builder_name': builder_name, 'configuration': configuration, 'webkit_test_runner': is_webkit2})
+ return optparse.Values({'builder_name': builder_name, 'configuration': configuration})
class PortFactory(object):
@@ -84,13 +75,8 @@
'chromium_linux.ChromiumLinuxPort',
'chromium_mac.ChromiumMacPort',
'chromium_win.ChromiumWinPort',
- 'efl.EflPort',
- 'gtk.GtkPort',
- 'mac.MacPort',
'mock_drt.MockDRTPort',
- 'qt.QtPort',
'test.TestPort',
- 'win.WinPort',
)
def __init__(self, host):
@@ -101,9 +87,9 @@
if platform.is_linux() or platform.is_freebsd():
return 'chromium-linux'
elif platform.is_mac():
- return 'mac'
+ return 'chromium-mac'
elif platform.is_win():
- return 'win'
+ return 'chromium-win'
raise NotImplementedError('unknown platform: %s' % platform)
def get(self, port_name=None, options=None, **kwargs):
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/factory_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/factory_unittest.py
index 363b7b9..32f3eb9 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/factory_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/factory_unittest.py
@@ -36,11 +36,7 @@
from webkitpy.layout_tests.port import chromium_mac
from webkitpy.layout_tests.port import chromium_win
from webkitpy.layout_tests.port import factory
-from webkitpy.layout_tests.port import gtk
-from webkitpy.layout_tests.port import mac
-from webkitpy.layout_tests.port import qt
from webkitpy.layout_tests.port import test
-from webkitpy.layout_tests.port import win
class FactoryTest(unittest.TestCase):
@@ -56,25 +52,6 @@
port = factory.PortFactory(host).get(port_name, options=options)
self.assertIsInstance(port, cls)
- def test_mac(self):
- self.assert_port(port_name='mac-lion', cls=mac.MacPort)
- self.assert_port(port_name='mac-lion-wk2', cls=mac.MacPort)
- self.assert_port(port_name='mac', os_name='mac', os_version='lion', cls=mac.MacPort)
- self.assert_port(port_name=None, os_name='mac', os_version='lion', cls=mac.MacPort)
-
- def test_win(self):
- self.assert_port(port_name='win-xp', cls=win.WinPort)
- self.assert_port(port_name='win-xp-wk2', cls=win.WinPort)
- self.assert_port(port_name='win', os_name='win', os_version='xp', cls=win.WinPort)
- self.assert_port(port_name=None, os_name='win', os_version='xp', cls=win.WinPort)
- self.assert_port(port_name=None, os_name='win', os_version='xp', options=self.webkit_options, cls=win.WinPort)
-
- def test_gtk(self):
- self.assert_port(port_name='gtk', cls=gtk.GtkPort)
-
- def test_qt(self):
- self.assert_port(port_name='qt', cls=qt.QtPort)
-
def test_chromium_mac(self):
self.assert_port(port_name='chromium-mac', os_name='mac', os_version='snowleopard',
cls=chromium_mac.ChromiumMacPort)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/gtk.py b/Tools/Scripts/webkitpy/layout_tests/port/gtk.py
deleted file mode 100644
index d2d799e..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/gtk.py
+++ /dev/null
@@ -1,179 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the Google name nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import os
-import subprocess
-
-from webkitpy.layout_tests.models.test_configuration import TestConfiguration
-from webkitpy.layout_tests.port.base import Port
-from webkitpy.layout_tests.port.pulseaudio_sanitizer import PulseAudioSanitizer
-from webkitpy.layout_tests.port.xvfbdriver import XvfbDriver
-
-
-class GtkPort(Port):
- port_name = "gtk"
-
- def __init__(self, *args, **kwargs):
- super(GtkPort, self).__init__(*args, **kwargs)
- self._pulseaudio_sanitizer = PulseAudioSanitizer()
-
- def warn_if_bug_missing_in_test_expectations(self):
- return True
-
- def _port_flag_for_scripts(self):
- return "--gtk"
-
- def _driver_class(self):
- return XvfbDriver
-
- def default_timeout_ms(self):
- if self.get_option('configuration') == 'Debug':
- return 12 * 1000
- return 6 * 1000
-
- def setup_test_run(self):
- super(GtkPort, self).setup_test_run()
- self._pulseaudio_sanitizer.unload_pulseaudio_module()
-
- def clean_up_test_run(self):
- super(GtkPort, self).clean_up_test_run()
- self._pulseaudio_sanitizer.restore_pulseaudio_module()
-
- def setup_environ_for_server(self, server_name=None):
- environment = super(GtkPort, self).setup_environ_for_server(server_name)
- environment['GTK_MODULES'] = 'gail'
- environment['GSETTINGS_BACKEND'] = 'memory'
- environment['LIBOVERLAY_SCROLLBAR'] = '0'
- environment['TEST_RUNNER_INJECTED_BUNDLE_FILENAME'] = self._build_path('Libraries', 'libTestRunnerInjectedBundle.la')
- environment['TEST_RUNNER_TEST_PLUGIN_PATH'] = self._build_path('TestNetscapePlugin', '.libs')
- environment['WEBKIT_INSPECTOR_PATH'] = self._build_path('Programs', 'resources', 'inspector')
- environment['AUDIO_RESOURCES_PATH'] = self.path_from_webkit_base('Source', 'WebCore', 'platform', 'audio', 'resources')
- self._copy_value_from_environ_if_set(environment, 'WEBKITOUTPUTDIR')
- return environment
-
- def _generate_all_test_configurations(self):
- configurations = []
- for build_type in self.ALL_BUILD_TYPES:
- configurations.append(TestConfiguration(version=self._version, architecture='x86', build_type=build_type))
- return configurations
-
- def _path_to_driver(self):
- return self._build_path('Programs', self.driver_name())
-
- def _path_to_image_diff(self):
- return self._build_path('Programs', 'ImageDiff')
-
- def _path_to_webcore_library(self):
- gtk_library_names = [
- "libwebkitgtk-1.0.so",
- "libwebkitgtk-3.0.so",
- "libwebkit2gtk-1.0.so",
- ]
-
- for library in gtk_library_names:
- full_library = self._build_path(".libs", library)
- if self._filesystem.isfile(full_library):
- return full_library
- return None
-
- def _search_paths(self):
- search_paths = []
- if self.get_option('webkit_test_runner'):
- search_paths.extend([self.port_name + '-wk2', 'wk2'])
- else:
- search_paths.append(self.port_name + '-wk1')
- search_paths.append(self.port_name)
- search_paths.extend(self.get_option("additional_platform_directory", []))
- return search_paths
-
- def default_baseline_search_path(self):
- return map(self._webkit_baseline_path, self._search_paths())
-
- def _port_specific_expectations_files(self):
- return [self._filesystem.join(self._webkit_baseline_path(p), 'TestExpectations') for p in reversed(self._search_paths())]
-
- # FIXME: We should find a way to share this implmentation with Gtk,
- # or teach run-launcher how to call run-safari and move this down to Port.
- def show_results_html_file(self, results_filename):
- run_launcher_args = ["file://%s" % results_filename]
- if self.get_option('webkit_test_runner'):
- run_launcher_args.append('-2')
- # FIXME: old-run-webkit-tests also added ["-graphicssystem", "raster", "-style", "windows"]
- # FIXME: old-run-webkit-tests converted results_filename path for cygwin.
- self._run_script("run-launcher", run_launcher_args)
-
- def check_sys_deps(self, needs_http):
- return super(GtkPort, self).check_sys_deps(needs_http) and XvfbDriver.check_xvfb(self)
-
- def _get_gdb_output(self, coredump_path):
- cmd = ['gdb', '-ex', 'thread apply all bt 1024', '--batch', str(self._path_to_driver()), coredump_path]
- proc = subprocess.Popen(cmd, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdout, stderr = proc.communicate()
- errors = [l.strip().decode('utf8', 'ignore') for l in stderr.splitlines()]
- return (stdout.decode('utf8', 'ignore'), errors)
-
- def _get_crash_log(self, name, pid, stdout, stderr, newer_than):
- pid_representation = str(pid or '<unknown>')
- log_directory = os.environ.get("WEBKIT_CORE_DUMPS_DIRECTORY")
- errors = []
- crash_log = ''
- expected_crash_dump_filename = "core-pid_%s-_-process_%s" % (pid_representation, name)
-
- def match_filename(filesystem, directory, filename):
- if pid:
- return filename == expected_crash_dump_filename
- return filename.find(name) > -1
-
- if log_directory:
- dumps = self._filesystem.files_under(log_directory, file_filter=match_filename)
- if dumps:
- # Get the most recent coredump matching the pid and/or process name.
- coredump_path = list(reversed(sorted(dumps)))[0]
- if not newer_than or self._filesystem.mtime(coredump_path) > newer_than:
- crash_log, errors = self._get_gdb_output(coredump_path)
-
- stderr_lines = errors + (stderr or '<empty>').decode('utf8', 'ignore').splitlines()
- errors_str = '\n'.join(('STDERR: ' + l) for l in stderr_lines)
- if not crash_log:
- if not log_directory:
- log_directory = "/path/to/coredumps"
- core_pattern = os.path.join(log_directory, "core-pid_%p-_-process_%e")
- crash_log = """\
-Coredump %(expected_crash_dump_filename)s not found. To enable crash logs:
-
-- run this command as super-user: echo "%(core_pattern)s" > /proc/sys/kernel/core_pattern
-- enable core dumps: ulimit -c unlimited
-- set the WEBKIT_CORE_DUMPS_DIRECTORY environment variable: export WEBKIT_CORE_DUMPS_DIRECTORY=%(log_directory)s
-
-""" % locals()
-
- return (stderr, """\
-Crash log for %(name)s (pid %(pid_representation)s):
-
-%(crash_log)s
-%(errors_str)s""" % locals())
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/gtk_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/gtk_unittest.py
deleted file mode 100644
index 7d24bb3..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/gtk_unittest.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# Copyright (C) 2011 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest2 as unittest
-import sys
-import os
-
-from webkitpy.common.system.executive_mock import MockExecutive
-from webkitpy.common.system.filesystem_mock import MockFileSystem
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.layout_tests.port.gtk import GtkPort
-from webkitpy.layout_tests.port.pulseaudio_sanitizer_mock import PulseAudioSanitizerMock
-from webkitpy.layout_tests.port import port_testcase
-from webkitpy.thirdparty.mock import Mock
-from webkitpy.tool.mocktool import MockOptions
-
-
-class GtkPortTest(port_testcase.PortTestCase):
- port_name = 'gtk'
- port_maker = GtkPort
-
- # Additionally mocks out the PulseAudioSanitizer methods.
- def make_port(self, host=None, port_name=None, options=None, os_name=None, os_version=None, **kwargs):
- port = super(GtkPortTest, self).make_port(host, port_name, options, os_name, os_version, **kwargs)
- port._pulseaudio_sanitizer = PulseAudioSanitizerMock()
- return port
-
- def test_default_baseline_search_path(self):
- port = self.make_port()
- self.assertEqual(port.default_baseline_search_path(), ['/mock-checkout/LayoutTests/platform/gtk-wk1',
- '/mock-checkout/LayoutTests/platform/gtk'])
-
- port = self.make_port(options=MockOptions(webkit_test_runner=True))
- self.assertEqual(port.default_baseline_search_path(), ['/mock-checkout/LayoutTests/platform/gtk-wk2',
- '/mock-checkout/LayoutTests/platform/wk2', '/mock-checkout/LayoutTests/platform/gtk'])
-
- def test_port_specific_expectations_files(self):
- port = self.make_port()
- self.assertEqual(port.expectations_files(), ['/mock-checkout/LayoutTests/TestExpectations',
- '/mock-checkout/LayoutTests/platform/gtk/TestExpectations',
- '/mock-checkout/LayoutTests/platform/gtk-wk1/TestExpectations'])
-
- port = self.make_port(options=MockOptions(webkit_test_runner=True))
- self.assertEqual(port.expectations_files(), ['/mock-checkout/LayoutTests/TestExpectations',
- '/mock-checkout/LayoutTests/platform/gtk/TestExpectations',
- '/mock-checkout/LayoutTests/platform/wk2/TestExpectations',
- '/mock-checkout/LayoutTests/platform/gtk-wk2/TestExpectations'])
-
- def test_show_results_html_file(self):
- port = self.make_port()
- port._executive = MockExecutive(should_log=True)
- expected_logs = "MOCK run_command: ['Tools/Scripts/run-launcher', '--release', '--gtk', 'file://test.html'], cwd=/mock-checkout\n"
- OutputCapture().assert_outputs(self, port.show_results_html_file, ["test.html"], expected_logs=expected_logs)
-
- def test_default_timeout_ms(self):
- self.assertEqual(self.make_port(options=MockOptions(configuration='Release')).default_timeout_ms(), 6000)
- self.assertEqual(self.make_port(options=MockOptions(configuration='Debug')).default_timeout_ms(), 12000)
-
- def test_get_crash_log(self):
- core_directory = os.environ.get('WEBKIT_CORE_DUMPS_DIRECTORY', '/path/to/coredumps')
- core_pattern = os.path.join(core_directory, "core-pid_%p-_-process_%e")
- mock_empty_crash_log = """\
-Crash log for DumpRenderTree (pid 28529):
-
-Coredump core-pid_28529-_-process_DumpRenderTree not found. To enable crash logs:
-
-- run this command as super-user: echo "%(core_pattern)s" > /proc/sys/kernel/core_pattern
-- enable core dumps: ulimit -c unlimited
-- set the WEBKIT_CORE_DUMPS_DIRECTORY environment variable: export WEBKIT_CORE_DUMPS_DIRECTORY=%(core_directory)s
-
-
-STDERR: <empty>""" % locals()
-
- def _mock_gdb_output(coredump_path):
- return (mock_empty_crash_log, [])
-
- port = self.make_port()
- port._get_gdb_output = mock_empty_crash_log
- stderr, log = port._get_crash_log("DumpRenderTree", 28529, "", "", newer_than=None)
- self.assertEqual(stderr, "")
- self.assertMultiLineEqual(log, mock_empty_crash_log)
-
- stderr, log = port._get_crash_log("DumpRenderTree", 28529, "", "", newer_than=0.0)
- self.assertEqual(stderr, "")
- self.assertMultiLineEqual(log, mock_empty_crash_log)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/leakdetector.py b/Tools/Scripts/webkitpy/layout_tests/port/leakdetector.py
deleted file mode 100644
index f46cd34..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/leakdetector.py
+++ /dev/null
@@ -1,153 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the Google name nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import logging
-import re
-
-from webkitpy.common.system.executive import ScriptError
-
-_log = logging.getLogger(__name__)
-
-
-# If other ports/platforms decide to support --leaks, we should see about sharing as much of this code as possible.
-# Right now this code is only used by Apple's MacPort.
-
-class LeakDetector(object):
- def __init__(self, port):
- # We should operate on a "platform" not a port here.
- self._port = port
- self._executive = port._executive
- self._filesystem = port._filesystem
-
- # We exclude the following reported leaks so they do not get in our way when looking for WebKit leaks:
- # This allows us ignore known leaks and only be alerted when new leaks occur. Some leaks are in the old
- # versions of the system frameworks that are being used by the leaks bots. Even though a leak has been
- # fixed, it will be listed here until the bot has been updated with the newer frameworks.
- def _types_to_exlude_from_leaks(self):
- # Currently we don't have any type excludes from OS leaks, but we will likely again in the future.
- return []
-
- def _callstacks_to_exclude_from_leaks(self):
- callstacks = [
- "Flash_EnforceLocalSecurity", # leaks in Flash plug-in code, rdar://problem/4449747
- "ScanFromString", # <http://code.google.com/p/angleproject/issues/detail?id=249> leak in ANGLE
- ]
- if self._port.is_snowleopard():
- callstacks += [
- "readMakerNoteProps", # <rdar://problem/7156432> leak in ImageIO
- "QTKitMovieControllerView completeUISetup", # <rdar://problem/7155156> leak in QTKit
- "getVMInitArgs", # <rdar://problem/7714444> leak in Java
- "Java_java_lang_System_initProperties", # <rdar://problem/7714465> leak in Java
- "glrCompExecuteKernel", # <rdar://problem/7815391> leak in graphics driver while using OpenGL
- "NSNumberFormatter getObjectValue:forString:errorDescription:", # <rdar://problem/7149350> Leak in NSNumberFormatter
- ]
- elif self._port.is_lion():
- callstacks += [
- "FigByteFlumeCustomURLCreateWithURL", # <rdar://problem/10461926> leak in CoreMedia
- "PDFPage\(PDFPageInternal\) pageLayoutIfAvail", # <rdar://problem/10462055> leak in PDFKit
- "SecTransformExecute", # <rdar://problem/10470667> leak in Security.framework
- "_NSCopyStyleRefForFocusRingStyleClip", # <rdar://problem/10462031> leak in AppKit
- ]
- return callstacks
-
- def _leaks_args(self, pid):
- leaks_args = []
- for callstack in self._callstacks_to_exclude_from_leaks():
- leaks_args += ['--exclude-callstack=%s' % callstack]
- for excluded_type in self._types_to_exlude_from_leaks():
- leaks_args += ['--exclude-type=%s' % excluded_type]
- leaks_args.append(pid)
- return leaks_args
-
- def _parse_leaks_output(self, leaks_output):
- _, count, bytes = re.search(r'Process (?P<pid>\d+): (?P<count>\d+) leaks? for (?P<bytes>\d+) total', leaks_output).groups()
- excluded_match = re.search(r'(?P<excluded>\d+) leaks? excluded', leaks_output)
- excluded = excluded_match.group('excluded') if excluded_match else 0
- return int(count), int(excluded), int(bytes)
-
- def leaks_files_in_directory(self, directory):
- return self._filesystem.glob(self._filesystem.join(directory, "*-leaks.txt"))
-
- def leaks_file_name(self, process_name, process_pid):
- # We include the number of files this worker has already written in the name to prevent overwritting previous leak results..
- return "%s-%s-leaks.txt" % (process_name, process_pid)
-
- def count_total_bytes_and_unique_leaks(self, leak_files):
- merge_depth = 5 # ORWT had a --merge-leak-depth argument, but that seems out of scope for the run-webkit-tests tool.
- args = [
- '--merge-depth',
- merge_depth,
- ] + leak_files
- try:
- parse_malloc_history_output = self._port._run_script("parse-malloc-history", args, include_configuration_arguments=False)
- except ScriptError, e:
- _log.warn("Failed to parse leaks output: %s" % e.message_with_output())
- return
-
- # total: 5,888 bytes (0 bytes excluded).
- unique_leak_count = len(re.findall(r'^(\d*)\scalls', parse_malloc_history_output, re.MULTILINE))
- total_bytes_string = re.search(r'^total\:\s(.+)\s\(', parse_malloc_history_output, re.MULTILINE).group(1)
- return (total_bytes_string, unique_leak_count)
-
- def count_total_leaks(self, leak_file_paths):
- total_leaks = 0
- for leak_file_path in leak_file_paths:
- # Leaks have been seen to include non-utf8 data, so we use read_binary_file.
- # See https://bugs.webkit.org/show_bug.cgi?id=71112.
- leaks_output = self._filesystem.read_binary_file(leak_file_path)
- count, _, _ = self._parse_leaks_output(leaks_output)
- total_leaks += count
- return total_leaks
-
- def check_for_leaks(self, process_name, process_pid):
- _log.debug("Checking for leaks in %s" % process_name)
- try:
- # Oddly enough, run-leaks (or the underlying leaks tool) does not seem to always output utf-8,
- # thus we pass decode_output=False. Without this code we've seen errors like:
- # "UnicodeDecodeError: 'utf8' codec can't decode byte 0x88 in position 779874: unexpected code byte"
- leaks_output = self._port._run_script("run-leaks", self._leaks_args(process_pid), include_configuration_arguments=False, decode_output=False)
- except ScriptError, e:
- _log.warn("Failed to run leaks tool: %s" % e.message_with_output())
- return
-
- # FIXME: We end up parsing this output 3 times. Once here and twice for summarizing.
- count, excluded, bytes = self._parse_leaks_output(leaks_output)
- adjusted_count = count - excluded
- if not adjusted_count:
- return
-
- leaks_filename = self.leaks_file_name(process_name, process_pid)
- leaks_output_path = self._filesystem.join(self._port.results_directory(), leaks_filename)
- self._filesystem.write_binary_file(leaks_output_path, leaks_output)
-
- # FIXME: Ideally we would not be logging from the worker process, but rather pass the leak
- # information back to the manager and have it log.
- if excluded:
- _log.info("%s leaks (%s bytes including %s excluded leaks) were found, details in %s" % (adjusted_count, bytes, excluded, leaks_output_path))
- else:
- _log.info("%s leaks (%s bytes) were found, details in %s" % (count, bytes, leaks_output_path))
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/leakdetector_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/leakdetector_unittest.py
deleted file mode 100644
index f2daec9..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/leakdetector_unittest.py
+++ /dev/null
@@ -1,152 +0,0 @@
-# Copyright (C) 2011 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest2 as unittest
-
-from webkitpy.layout_tests.port.leakdetector import LeakDetector
-from webkitpy.common.system.filesystem_mock import MockFileSystem
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.common.system.executive_mock import MockExecutive
-
-
-class LeakDetectorTest(unittest.TestCase):
- def _mock_port(self):
- class MockPort(object):
- def __init__(self):
- self._filesystem = MockFileSystem()
- self._executive = MockExecutive()
-
- return MockPort()
-
- def _make_detector(self):
- return LeakDetector(self._mock_port())
-
- def test_leaks_args(self):
- detector = self._make_detector()
- detector._callstacks_to_exclude_from_leaks = lambda: ['foo bar', 'BAZ']
- detector._types_to_exlude_from_leaks = lambda: ['abcdefg', 'hi jklmno']
- expected_args = ['--exclude-callstack=foo bar', '--exclude-callstack=BAZ', '--exclude-type=abcdefg', '--exclude-type=hi jklmno', 1234]
- self.assertEqual(detector._leaks_args(1234), expected_args)
-
- example_leaks_output = """Process 5122: 663744 nodes malloced for 78683 KB
-Process 5122: 337301 leaks for 6525216 total leaked bytes.
-Leak: 0x38cb600 size=3072 zone: DefaultMallocZone_0x1d94000 instance of 'NSCFData', type ObjC, implemented in Foundation
- 0xa033f0b8 0x01001384 0x00000b3a 0x00000b3a ..3.....:...:...
- 0x00000000 0x038cb620 0x00000000 0x00000000 .... ...........
- 0x00000000 0x21000000 0x726c6468 0x00000000 .......!hdlr....
- 0x00000000 0x7269646d 0x6c707061 0x00000000 ....mdirappl....
- 0x00000000 0x04000000 0x736c69c1 0x00000074 .........ilst...
- 0x6f74a923 0x0000006f 0x7461641b 0x00000061 #.too....data...
- 0x00000001 0x76614c00 0x2e323566 0x302e3236 .....Lavf52.62.0
- 0x37000000 0x6d616ea9 0x2f000000 0x61746164 ...7.nam.../data
- ...
-Leak: 0x2a9c960 size=288 zone: DefaultMallocZone_0x1d94000
- 0x09a1cc47 0x1bda8560 0x3d472cd1 0xfbe9bccd G...`....,G=....
- 0x8bcda008 0x9e972a91 0xa892cf63 0x2448bdb0 .....*..c.....H$
- 0x4736fc34 0xdbe2d94e 0x25f56688 0x839402a4 4.6GN....f.%....
- 0xd12496b3 0x59c40c12 0x8cfcab2a 0xd20ef9c4 ..$....Y*.......
- 0xe7c56b1b 0x5835af45 0xc69115de 0x6923e4bb .k..E.5X......#i
- 0x86f15553 0x15d40fa9 0x681288a4 0xc33298a9 SU.........h..2.
- 0x439bb535 0xc4fc743d 0x7dfaaff8 0x2cc49a4a 5..C=t.....}J..,
- 0xdd119df8 0x7e086821 0x3d7d129e 0x2e1b1547 ....!h.~..}=G...
- ...
-Leak: 0x25102fe0 size=176 zone: DefaultMallocZone_0x1d94000 string 'NSException Data'
-"""
-
- example_leaks_output_with_exclusions = """
-Process 57064: 865808 nodes malloced for 81032 KB
-Process 57064: 282 leaks for 21920 total leaked bytes.
-Leak: 0x7fc506023960 size=576 zone: DefaultMallocZone_0x107c29000 URLConnectionLoader::LoaderConnectionEventQueue C++ CFNetwork
- 0x73395460 0x00007fff 0x7488af40 0x00007fff `T9s....@..t....
- 0x73395488 0x00007fff 0x46eecd74 0x0001ed83 .T9s....t..F....
- 0x0100000a 0x00000000 0x7488bfc0 0x00007fff ...........t....
- 0x00000000 0x00000000 0x46eecd8b 0x0001ed83 ...........F....
- 0x00000000 0x00000000 0x00000000 0x00000000 ................
- 0x00000000 0x00000000 0x46eecda3 0x0001ed83 ...........F....
- 0x00000000 0x00000000 0x00000000 0x00000000 ................
- 0x00000000 0x00000000 0x46eecdbc 0x0001ed83 ...........F....
- ...
-Leak: 0x7fc506025980 size=432 zone: DefaultMallocZone_0x107c29000 URLConnectionInstanceData CFType CFNetwork
- 0x74862b28 0x00007fff 0x00012b80 0x00000001 (+.t.....+......
- 0x73395310 0x00007fff 0x733953f8 0x00007fff .S9s.....S9s....
- 0x4d555458 0x00000000 0x00000000 0x00002068 XTUM........h ..
- 0x00000000 0x00000000 0x00000b00 0x00000b00 ................
- 0x00000000 0x00000000 0x060259b8 0x00007fc5 .........Y......
- 0x060259bc 0x00007fc5 0x00000000 0x00000000 .Y..............
- 0x73395418 0x00007fff 0x06025950 0x00007fc5 .T9s....PY......
- 0x73395440 0x00007fff 0x00005013 0x00000001 @T9s.....P......
- ...
-
-
-Binary Images:
- 0x107ac2000 - 0x107b4aff7 +DumpRenderTree (??? - ???) <5694BE03-A60A-30B2-9D40-27CFFCFB88EE> /Volumes/Data/WebKit-BuildSlave/lion-intel-leaks/build/WebKitBuild/Debug/DumpRenderTree
- 0x107c2f000 - 0x107c58fff +libWebCoreTestSupport.dylib (535.8.0 - compatibility 1.0.0) <E4F7A13E-5807-30F7-A399-62F8395F9106> /Volumes/Data/WebKit-BuildSlave/lion-intel-leaks/build/WebKitBuild/Debug/libWebCoreTestSupport.dylib
-17 leaks excluded (not printed)
-"""
-
- def test_parse_leaks_output(self):
- self.assertEqual(self._make_detector()._parse_leaks_output(self.example_leaks_output), (337301, 0, 6525216))
- self.assertEqual(self._make_detector()._parse_leaks_output(self.example_leaks_output_with_exclusions), (282, 17, 21920))
-
- def test_leaks_files_in_directory(self):
- detector = self._make_detector()
- self.assertEqual(detector.leaks_files_in_directory('/bogus-directory'), [])
- detector._filesystem = MockFileSystem({
- '/mock-results/DumpRenderTree-1234-leaks.txt': '',
- '/mock-results/DumpRenderTree-23423-leaks.txt': '',
- '/mock-results/DumpRenderTree-823-leaks.txt': '',
- })
- self.assertEqual(len(detector.leaks_files_in_directory('/mock-results')), 3)
-
- def test_count_total_bytes_and_unique_leaks(self):
- detector = self._make_detector()
-
- def mock_run_script(name, args, include_configuration_arguments=False):
- print "MOCK _run_script: %s %s" % (name, args)
- return """1 calls for 16 bytes: -[NSURLRequest mutableCopyWithZone:] | +[NSObject(NSObject) allocWithZone:] | _internal_class_createInstanceFromZone | calloc | malloc_zone_calloc
-
-147 calls for 9,408 bytes: _CFRuntimeCreateInstance | _ZN3WTF24StringWrapperCFAllocatorL8allocateElmPv StringImplCF.cpp:67 | WTF::fastMalloc(unsigned long) FastMalloc.cpp:268 | malloc | malloc_zone_malloc
-
-total: 5,888 bytes (0 bytes excluded)."""
- detector._port._run_script = mock_run_script
-
- leak_files = ['/mock-results/DumpRenderTree-1234-leaks.txt', '/mock-results/DumpRenderTree-1235-leaks.txt']
- expected_stdout = "MOCK _run_script: parse-malloc-history ['--merge-depth', 5, '/mock-results/DumpRenderTree-1234-leaks.txt', '/mock-results/DumpRenderTree-1235-leaks.txt']\n"
- results_tuple = OutputCapture().assert_outputs(self, detector.count_total_bytes_and_unique_leaks, [leak_files], expected_stdout=expected_stdout)
- self.assertEqual(results_tuple, ("5,888 bytes", 2))
-
- def test_count_total_leaks(self):
- detector = self._make_detector()
- detector._filesystem = MockFileSystem({
- # The \xff is some non-utf8 characters to make sure we don't blow up trying to parse the file.
- '/mock-results/DumpRenderTree-1234-leaks.txt': '\xff\nProcess 1234: 12 leaks for 40 total leaked bytes.\n\xff\n',
- '/mock-results/DumpRenderTree-23423-leaks.txt': 'Process 1235: 12341 leaks for 27934 total leaked bytes.\n',
- '/mock-results/DumpRenderTree-823-leaks.txt': 'Process 12356: 23412 leaks for 18 total leaked bytes.\n',
- })
- leak_file_paths = ['/mock-results/DumpRenderTree-1234-leaks.txt', '/mock-results/DumpRenderTree-23423-leaks.txt', '/mock-results/DumpRenderTree-823-leaks.txt']
- self.assertEqual(detector.count_total_leaks(leak_file_paths), 35765)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mac.py b/Tools/Scripts/webkitpy/layout_tests/port/mac.py
deleted file mode 100644
index 031a239..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/mac.py
+++ /dev/null
@@ -1,297 +0,0 @@
-# Copyright (C) 2011 Google Inc. All rights reserved.
-# Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the Google name nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import logging
-import os
-import time
-
-from webkitpy.common.system.crashlogs import CrashLogs
-from webkitpy.common.system.executive import ScriptError
-from webkitpy.layout_tests.port.apple import ApplePort
-from webkitpy.layout_tests.port.leakdetector import LeakDetector
-
-
-_log = logging.getLogger(__name__)
-
-
-class MacPort(ApplePort):
- port_name = "mac"
-
- VERSION_FALLBACK_ORDER = ['mac-snowleopard', 'mac-lion', 'mac-mountainlion']
-
- ARCHITECTURES = ['x86_64', 'x86']
-
- def __init__(self, host, port_name, **kwargs):
- ApplePort.__init__(self, host, port_name, **kwargs)
- self._architecture = self.get_option('architecture')
-
- if not self._architecture:
- self._architecture = 'x86_64'
-
- self._leak_detector = LeakDetector(self)
- if self.get_option("leaks"):
- # DumpRenderTree slows down noticably if we run more than about 1000 tests in a batch
- # with MallocStackLogging enabled.
- self.set_option_default("batch_size", 1000)
-
- def default_timeout_ms(self):
- if self.get_option('guard_malloc'):
- return 350 * 1000
- return super(MacPort, self).default_timeout_ms()
-
- def supports_per_test_timeout(self):
- return True
-
- def _build_driver_flags(self):
- return ['ARCHS=i386'] if self.architecture() == 'x86' else []
-
- def should_retry_crashes(self):
- # On Apple Mac, we retry crashes due to https://bugs.webkit.org/show_bug.cgi?id=82233
- return True
-
- def default_baseline_search_path(self):
- name = self._name.replace('-wk2', '')
- if name.endswith(self.FUTURE_VERSION):
- fallback_names = [self.port_name]
- else:
- fallback_names = self.VERSION_FALLBACK_ORDER[self.VERSION_FALLBACK_ORDER.index(name):-1] + [self.port_name]
- if self.get_option('webkit_test_runner'):
- fallback_names = [self._wk2_port_name(), 'wk2'] + fallback_names
- return map(self._webkit_baseline_path, fallback_names)
-
- def _port_specific_expectations_files(self):
- return list(reversed([self._filesystem.join(self._webkit_baseline_path(p), 'TestExpectations') for p in self.baseline_search_path()]))
-
- def setup_environ_for_server(self, server_name=None):
- env = super(MacPort, self).setup_environ_for_server(server_name)
- if server_name == self.driver_name():
- if self.get_option('leaks'):
- env['MallocStackLogging'] = '1'
- if self.get_option('guard_malloc'):
- env['DYLD_INSERT_LIBRARIES'] = '/usr/lib/libgmalloc.dylib'
- env['XML_CATALOG_FILES'] = '' # work around missing /etc/catalog <rdar://problem/4292995>
- return env
-
- def operating_system(self):
- return 'mac'
-
- # Belongs on a Platform object.
- def is_snowleopard(self):
- return self._version == "snowleopard"
-
- # Belongs on a Platform object.
- def is_lion(self):
- return self._version == "lion"
-
- def default_child_processes(self):
- if self._version == "snowleopard":
- _log.warning("Cannot run tests in parallel on Snow Leopard due to rdar://problem/10621525.")
- return 1
-
- default_count = super(MacPort, self).default_child_processes()
-
- # FIXME: https://bugs.webkit.org/show_bug.cgi?id=95906 With too many WebProcess WK2 tests get stuck in resource contention.
- # To alleviate the issue reduce the number of running processes
- # Anecdotal evidence suggests that a 4 core/8 core logical machine may run into this, but that a 2 core/4 core logical machine does not.
- if self.get_option('webkit_test_runner') and default_count > 4:
- default_count = int(.75 * default_count)
-
- # Make sure we have enough ram to support that many instances:
- total_memory = self.host.platform.total_bytes_memory()
- bytes_per_drt = 256 * 1024 * 1024 # Assume each DRT needs 256MB to run.
- overhead = 2048 * 1024 * 1024 # Assume we need 2GB free for the O/S
- supportable_instances = max((total_memory - overhead) / bytes_per_drt, 1) # Always use one process, even if we don't have space for it.
- if supportable_instances < default_count:
- _log.warning("This machine could support %s child processes, but only has enough memory for %s." % (default_count, supportable_instances))
- return min(supportable_instances, default_count)
-
- def _build_java_test_support(self):
- java_tests_path = self._filesystem.join(self.layout_tests_dir(), "java")
- build_java = [self.make_command(), "-C", java_tests_path]
- if self._executive.run_command(build_java, return_exit_code=True): # Paths are absolute, so we don't need to set a cwd.
- _log.error("Failed to build Java support files: %s" % build_java)
- return False
- return True
-
- def check_for_leaks(self, process_name, process_pid):
- if not self.get_option('leaks'):
- return
- # We could use http://code.google.com/p/psutil/ to get the process_name from the pid.
- self._leak_detector.check_for_leaks(process_name, process_pid)
-
- def print_leaks_summary(self):
- if not self.get_option('leaks'):
- return
- # We're in the manager process, so the leak detector will not have a valid list of leak files.
- # FIXME: This is a hack, but we don't have a better way to get this information from the workers yet.
- # FIXME: This will include too many leaks in subsequent runs until the results directory is cleared!
- leaks_files = self._leak_detector.leaks_files_in_directory(self.results_directory())
- if not leaks_files:
- return
- total_bytes_string, unique_leaks = self._leak_detector.count_total_bytes_and_unique_leaks(leaks_files)
- total_leaks = self._leak_detector.count_total_leaks(leaks_files)
- _log.info("%s total leaks found for a total of %s!" % (total_leaks, total_bytes_string))
- _log.info("%s unique leaks found!" % unique_leaks)
-
- def _check_port_build(self):
- return self._build_java_test_support()
-
- def _path_to_webcore_library(self):
- return self._build_path('WebCore.framework/Versions/A/WebCore')
-
- def show_results_html_file(self, results_filename):
- # We don't use self._run_script() because we don't want to wait for the script
- # to exit and we want the output to show up on stdout in case there are errors
- # launching the browser.
- self._executive.popen([self.path_to_script('run-safari')] + self._arguments_for_configuration() + ['--no-saved-state', '-NSOpen', results_filename],
- cwd=self.webkit_base(), stdout=file(os.devnull), stderr=file(os.devnull))
-
- # FIXME: The next two routines turn off the http locking in order
- # to work around failures on the bots caused when the slave restarts.
- # See https://bugs.webkit.org/show_bug.cgi?id=64886 for more info.
- # The proper fix is to make sure the slave is actually stopping NRWT
- # properly on restart. Note that by removing the lock file and not waiting,
- # the result should be that if there is a web server already running,
- # it'll be killed and this one will be started in its place; this
- # may lead to weird things happening in the other run. However, I don't
- # think we're (intentionally) actually running multiple runs concurrently
- # on any Mac bots.
-
- def acquire_http_lock(self):
- pass
-
- def release_http_lock(self):
- pass
-
- def sample_file_path(self, name, pid):
- return self._filesystem.join(self.results_directory(), "{0}-{1}-sample.txt".format(name, pid))
-
- def _get_crash_log(self, name, pid, stdout, stderr, newer_than, time_fn=None, sleep_fn=None, wait_for_log=True):
- # Note that we do slow-spin here and wait, since it appears the time
- # ReportCrash takes to actually write and flush the file varies when there are
- # lots of simultaneous crashes going on.
- # FIXME: Should most of this be moved into CrashLogs()?
- time_fn = time_fn or time.time
- sleep_fn = sleep_fn or time.sleep
- crash_log = ''
- crash_logs = CrashLogs(self.host)
- now = time_fn()
- # FIXME: delete this after we're sure this code is working ...
- _log.debug('looking for crash log for %s:%s' % (name, str(pid)))
- deadline = now + 5 * int(self.get_option('child_processes', 1))
- while not crash_log and now <= deadline:
- crash_log = crash_logs.find_newest_log(name, pid, include_errors=True, newer_than=newer_than)
- if not wait_for_log:
- break
- if not crash_log or not [line for line in crash_log.splitlines() if not line.startswith('ERROR')]:
- sleep_fn(0.1)
- now = time_fn()
-
- if not crash_log:
- return (stderr, None)
- return (stderr, crash_log)
-
- def look_for_new_crash_logs(self, crashed_processes, start_time):
- """Since crash logs can take a long time to be written out if the system is
- under stress do a second pass at the end of the test run.
-
- crashes: test_name -> pid, process_name tuple of crashed process
- start_time: time the tests started at. We're looking for crash
- logs after that time.
- """
- crash_logs = {}
- for (test_name, process_name, pid) in crashed_processes:
- # Passing None for output. This is a second pass after the test finished so
- # if the output had any logging we would have already collected it.
- crash_log = self._get_crash_log(process_name, pid, None, None, start_time, wait_for_log=False)[1]
- if not crash_log:
- continue
- crash_logs[test_name] = crash_log
- return crash_logs
-
- def look_for_new_samples(self, unresponsive_processes, start_time):
- sample_files = {}
- for (test_name, process_name, pid) in unresponsive_processes:
- sample_file = self.sample_file_path(process_name, pid)
- if not self._filesystem.isfile(sample_file):
- continue
- sample_files[test_name] = sample_file
- return sample_files
-
- def sample_process(self, name, pid):
- try:
- hang_report = self.sample_file_path(name, pid)
- self._executive.run_command([
- "/usr/bin/sample",
- pid,
- 10,
- 10,
- "-file",
- hang_report,
- ])
- except ScriptError as e:
- _log.warning('Unable to sample process:' + str(e))
-
- def _path_to_helper(self):
- binary_name = 'LayoutTestHelper'
- return self._build_path(binary_name)
-
- def start_helper(self):
- helper_path = self._path_to_helper()
- if helper_path:
- _log.debug("Starting layout helper %s" % helper_path)
- self._helper = self._executive.popen([helper_path],
- stdin=self._executive.PIPE, stdout=self._executive.PIPE, stderr=None)
- is_ready = self._helper.stdout.readline()
- if not is_ready.startswith('ready'):
- _log.error("LayoutTestHelper failed to be ready")
-
- def stop_helper(self):
- if self._helper:
- _log.debug("Stopping LayoutTestHelper")
- try:
- self._helper.stdin.write("x\n")
- self._helper.stdin.close()
- self._helper.wait()
- except IOError, e:
- _log.debug("IOError raised while stopping helper: %s" % str(e))
- self._helper = None
-
- def make_command(self):
- return self.xcrun_find('make', '/usr/bin/make')
-
- def nm_command(self):
- return self.xcrun_find('nm', 'nm')
-
- def xcrun_find(self, command, fallback):
- try:
- return self._executive.run_command(['xcrun', '-find', command]).rstrip()
- except ScriptError:
- _log.warn("xcrun failed; falling back to '%s'." % fallback)
- return fallback
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py
deleted file mode 100644
index 3faf9c1..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py
+++ /dev/null
@@ -1,257 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-from webkitpy.layout_tests.port.mac import MacPort
-from webkitpy.layout_tests.port import port_testcase
-from webkitpy.common.system.filesystem_mock import MockFileSystem
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.tool.mocktool import MockOptions
-from webkitpy.common.system.executive_mock import MockExecutive, MockExecutive2, MockProcess, ScriptError
-from webkitpy.common.system.systemhost_mock import MockSystemHost
-
-
-class MacTest(port_testcase.PortTestCase):
- os_name = 'mac'
- os_version = 'lion'
- port_name = 'mac-lion'
- port_maker = MacPort
-
- def assert_skipped_file_search_paths(self, port_name, expected_paths, use_webkit2=False):
- port = self.make_port(port_name=port_name, options=MockOptions(webkit_test_runner=use_webkit2))
- self.assertEqual(port._skipped_file_search_paths(), expected_paths)
-
- def test_default_timeout_ms(self):
- super(MacTest, self).test_default_timeout_ms()
- self.assertEqual(self.make_port(options=MockOptions(guard_malloc=True)).default_timeout_ms(), 350000)
-
-
- example_skipped_file = u"""
-# <rdar://problem/5647952> fast/events/mouseout-on-window.html needs mac DRT to issue mouse out events
-fast/events/mouseout-on-window.html
-
-# <rdar://problem/5643675> window.scrollTo scrolls a window with no scrollbars
-fast/events/attempt-scroll-with-no-scrollbars.html
-
-# see bug <rdar://problem/5646437> REGRESSION (r28015): svg/batik/text/smallFonts fails
-svg/batik/text/smallFonts.svg
-
-# Java tests don't work on WK2
-java/
-"""
- example_skipped_tests = [
- "fast/events/mouseout-on-window.html",
- "fast/events/attempt-scroll-with-no-scrollbars.html",
- "svg/batik/text/smallFonts.svg",
- "java",
- ]
-
- def test_tests_from_skipped_file_contents(self):
- port = self.make_port()
- self.assertEqual(port._tests_from_skipped_file_contents(self.example_skipped_file), self.example_skipped_tests)
-
- def assert_name(self, port_name, os_version_string, expected):
- host = MockSystemHost(os_name='mac', os_version=os_version_string)
- port = self.make_port(host=host, port_name=port_name)
- self.assertEqual(expected, port.name())
-
- def test_tests_for_other_platforms(self):
- platforms = ['mac', 'chromium-linux', 'mac-snowleopard']
- port = self.make_port(port_name='mac-snowleopard')
- platform_dir_paths = map(port._webkit_baseline_path, platforms)
- # Replace our empty mock file system with one which has our expected platform directories.
- port._filesystem = MockFileSystem(dirs=platform_dir_paths)
-
- dirs_to_skip = port._tests_for_other_platforms()
- self.assertIn('platform/chromium-linux', dirs_to_skip)
- self.assertNotIn('platform/mac', dirs_to_skip)
- self.assertNotIn('platform/mac-snowleopard', dirs_to_skip)
-
- def test_version(self):
- port = self.make_port()
- self.assertTrue(port.version())
-
- def test_versions(self):
- # Note: these tests don't need to be exhaustive as long as we get path coverage.
- self.assert_name('mac', 'snowleopard', 'mac-snowleopard')
- self.assert_name('mac-snowleopard', 'leopard', 'mac-snowleopard')
- self.assert_name('mac-snowleopard', 'lion', 'mac-snowleopard')
-
- self.assert_name('mac', 'lion', 'mac-lion')
- self.assert_name('mac-lion', 'lion', 'mac-lion')
-
- self.assert_name('mac', 'mountainlion', 'mac-mountainlion')
- self.assert_name('mac-mountainlion', 'lion', 'mac-mountainlion')
-
- self.assert_name('mac', 'future', 'mac-future')
- self.assert_name('mac-future', 'future', 'mac-future')
-
- self.assertRaises(AssertionError, self.assert_name, 'mac-tiger', 'leopard', 'mac-leopard')
-
- def test_setup_environ_for_server(self):
- port = self.make_port(options=MockOptions(leaks=True, guard_malloc=True))
- env = port.setup_environ_for_server(port.driver_name())
- self.assertEqual(env['MallocStackLogging'], '1')
- self.assertEqual(env['DYLD_INSERT_LIBRARIES'], '/usr/lib/libgmalloc.dylib')
-
- def _assert_search_path(self, port_name, baseline_path, search_paths, use_webkit2=False):
- port = self.make_port(port_name=port_name, options=MockOptions(webkit_test_runner=use_webkit2))
- absolute_search_paths = map(port._webkit_baseline_path, search_paths)
- self.assertEqual(port.baseline_path(), port._webkit_baseline_path(baseline_path))
- self.assertEqual(port.baseline_search_path(), absolute_search_paths)
-
- def test_baseline_search_path(self):
- # Note that we don't need total coverage here, just path coverage, since this is all data driven.
- self._assert_search_path('mac-snowleopard', 'mac-snowleopard', ['mac-snowleopard', 'mac-lion', 'mac'])
- self._assert_search_path('mac-lion', 'mac-lion', ['mac-lion', 'mac'])
- self._assert_search_path('mac-mountainlion', 'mac', ['mac'])
- self._assert_search_path('mac-future', 'mac', ['mac'])
- self._assert_search_path('mac-snowleopard', 'mac-wk2', ['mac-wk2', 'wk2', 'mac-snowleopard', 'mac-lion', 'mac'], use_webkit2=True)
- self._assert_search_path('mac-lion', 'mac-wk2', ['mac-wk2', 'wk2', 'mac-lion', 'mac'], use_webkit2=True)
- self._assert_search_path('mac-mountainlion', 'mac-wk2', ['mac-wk2', 'wk2', 'mac'], use_webkit2=True)
- self._assert_search_path('mac-future', 'mac-wk2', ['mac-wk2', 'wk2', 'mac'], use_webkit2=True)
-
- def test_show_results_html_file(self):
- port = self.make_port()
- # Delay setting a should_log executive to avoid logging from MacPort.__init__.
- port._executive = MockExecutive(should_log=True)
- expected_logs = "MOCK popen: ['Tools/Scripts/run-safari', '--release', '--no-saved-state', '-NSOpen', 'test.html'], cwd=/mock-checkout\n"
- OutputCapture().assert_outputs(self, port.show_results_html_file, ["test.html"], expected_logs=expected_logs)
-
- def test_operating_system(self):
- self.assertEqual('mac', self.make_port().operating_system())
-
- def test_default_child_processes(self):
- port = self.make_port(port_name='mac-lion')
- # MockPlatformInfo only has 2 mock cores. The important part is that 2 > 1.
- self.assertEqual(port.default_child_processes(), 2)
-
- bytes_for_drt = 200 * 1024 * 1024
- port.host.platform.total_bytes_memory = lambda: bytes_for_drt
- expected_logs = "This machine could support 2 child processes, but only has enough memory for 1.\n"
- child_processes = OutputCapture().assert_outputs(self, port.default_child_processes, (), expected_logs=expected_logs)
- self.assertEqual(child_processes, 1)
-
- # Make sure that we always use one process, even if we don't have the memory for it.
- port.host.platform.total_bytes_memory = lambda: bytes_for_drt - 1
- expected_logs = "This machine could support 2 child processes, but only has enough memory for 1.\n"
- child_processes = OutputCapture().assert_outputs(self, port.default_child_processes, (), expected_logs=expected_logs)
- self.assertEqual(child_processes, 1)
-
- # SnowLeopard has a CFNetwork bug which causes crashes if we execute more than one copy of DRT at once.
- port = self.make_port(port_name='mac-snowleopard')
- expected_logs = "Cannot run tests in parallel on Snow Leopard due to rdar://problem/10621525.\n"
- child_processes = OutputCapture().assert_outputs(self, port.default_child_processes, (), expected_logs=expected_logs)
- self.assertEqual(child_processes, 1)
-
- def test_get_crash_log(self):
- # Mac crash logs are tested elsewhere, so here we just make sure we don't crash.
- def fake_time_cb():
- times = [0, 20, 40]
- return lambda: times.pop(0)
- port = self.make_port(port_name='mac-snowleopard')
- port._get_crash_log('DumpRenderTree', 1234, '', '', 0,
- time_fn=fake_time_cb(), sleep_fn=lambda delay: None)
-
- def test_helper_starts(self):
- host = MockSystemHost(MockExecutive())
- port = self.make_port(host)
- oc = OutputCapture()
- oc.capture_output()
- host.executive._proc = MockProcess('ready\n')
- port.start_helper()
- port.stop_helper()
- oc.restore_output()
-
- # make sure trying to stop the helper twice is safe.
- port.stop_helper()
-
- def test_helper_fails_to_start(self):
- host = MockSystemHost(MockExecutive())
- port = self.make_port(host)
- oc = OutputCapture()
- oc.capture_output()
- port.start_helper()
- port.stop_helper()
- oc.restore_output()
-
- def test_helper_fails_to_stop(self):
- host = MockSystemHost(MockExecutive())
- host.executive._proc = MockProcess()
-
- def bad_waiter():
- raise IOError('failed to wait')
- host.executive._proc.wait = bad_waiter
-
- port = self.make_port(host)
- oc = OutputCapture()
- oc.capture_output()
- port.start_helper()
- port.stop_helper()
- oc.restore_output()
-
- def test_sample_process(self):
-
- def logging_run_command(args):
- print args
-
- port = self.make_port()
- port._executive = MockExecutive2(run_command_fn=logging_run_command)
- expected_stdout = "['/usr/bin/sample', 42, 10, 10, '-file', '/mock-build/layout-test-results/test-42-sample.txt']\n"
- OutputCapture().assert_outputs(self, port.sample_process, args=['test', 42], expected_stdout=expected_stdout)
-
- def test_sample_process_throws_exception(self):
-
- def throwing_run_command(args):
- raise ScriptError("MOCK script error")
-
- port = self.make_port()
- port._executive = MockExecutive2(run_command_fn=throwing_run_command)
- OutputCapture().assert_outputs(self, port.sample_process, args=['test', 42])
-
- def test_32bit(self):
- port = self.make_port(options=MockOptions(architecture='x86'))
-
- def run_script(script, args=None, env=None):
- self.args = args
-
- port._run_script = run_script
- self.assertEqual(port.architecture(), 'x86')
- port._build_driver()
- self.assertEqual(self.args, ['ARCHS=i386'])
-
- def test_64bit(self):
- # Apple Mac port is 64-bit by default
- port = self.make_port()
- self.assertEqual(port.architecture(), 'x86_64')
-
- def run_script(script, args=None, env=None):
- self.args = args
-
- port._run_script = run_script
- port._build_driver()
- self.assertEqual(self.args, [])
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py
index bd285ef..c882868 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py
@@ -48,7 +48,7 @@
def make_port(self, options=mock_options):
host = MockSystemHost()
test.add_unit_tests_to_mock_filesystem(host.filesystem)
- return mock_drt.MockDRTPort(host, port_name='mock-mac-lion', options=options)
+ return mock_drt.MockDRTPort(host, port_name='mock-chromium-mac', options=options)
def test_port_name_in_constructor(self):
self.assertTrue(mock_drt.MockDRTPort(MockSystemHost(), port_name='mock-test'))
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py b/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
index df480d4..2573608 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
@@ -99,11 +99,11 @@
self.assertEqual(port.default_max_locked_shards(), 1)
def test_default_timeout_ms(self):
- self.assertEqual(self.make_port(options=MockOptions(configuration='Release')).default_timeout_ms(), 35000)
- self.assertEqual(self.make_port(options=MockOptions(configuration='Debug')).default_timeout_ms(), 35000)
+ self.assertEqual(self.make_port(options=MockOptions(configuration='Release')).default_timeout_ms(), 6000)
+ self.assertEqual(self.make_port(options=MockOptions(configuration='Debug')).default_timeout_ms(), 12000)
def test_default_pixel_tests(self):
- self.assertEqual(self.make_port().default_pixel_tests(), False)
+ self.assertEqual(self.make_port().default_pixel_tests(), True)
def test_driver_cmd_line(self):
port = self.make_port()
@@ -219,7 +219,7 @@
def integration_test_image_diff(self):
port = self.make_port()
- # FIXME: This test will never run since we are using a MockFilesystem for these tests!?!?
+ # FIXME: This test will never run since we are using MockFileSystem for these tests!?!?
if not port.check_image_diff():
# The port hasn't been built - don't run the tests.
return
@@ -425,7 +425,6 @@
port._filesystem.write_text_file(path, '')
ordered_dict = port.expectations_dict()
self.assertEqual(port.path_to_generic_test_expectations_file(), ordered_dict.keys()[0])
- self.assertEqual(port.path_to_test_expectations_file(), ordered_dict.keys()[1])
options = MockOptions(additional_expectations=['/tmp/foo', '/tmp/bar'])
port = self.make_port(options=options)
@@ -437,20 +436,6 @@
self.assertEqual(ordered_dict.keys()[-2:], options.additional_expectations) # pylint: disable=E1101
self.assertEqual(ordered_dict.values()[-2:], ['foo', 'bar'])
- def test_path_to_test_expectations_file(self):
- port = TestWebKitPort()
- port._options = MockOptions(webkit_test_runner=False)
- self.assertEqual(port.path_to_test_expectations_file(), '/mock-checkout/LayoutTests/platform/testwebkitport/TestExpectations')
-
- port = TestWebKitPort()
- port._options = MockOptions(webkit_test_runner=True)
- self.assertEqual(port.path_to_test_expectations_file(), '/mock-checkout/LayoutTests/platform/testwebkitport/TestExpectations')
-
- port = TestWebKitPort()
- port.host.filesystem.files['/mock-checkout/LayoutTests/platform/testwebkitport/TestExpectations'] = 'some content'
- port._options = MockOptions(webkit_test_runner=False)
- self.assertEqual(port.path_to_test_expectations_file(), '/mock-checkout/LayoutTests/platform/testwebkitport/TestExpectations')
-
def test_skipped_directories_for_symbols(self):
# This first test confirms that the commonly found symbols result in the expected skipped directories.
symbols_string = " ".join(["GraphicsLayer", "WebCoreHas3DRendering", "isXHTMLMPDocument", "fooSymbol"])
@@ -475,7 +460,7 @@
000000000124f670 s __ZZN7WebCore13GraphicsLayer13addChildBelowEPS0_S1_E19__PRETTY_FUNCTION__
"""
# Note 'compositing' is not in the list of skipped directories (hence the parsing of GraphicsLayer worked):
- expected_directories = set(['mathml', 'transforms/3d', 'compositing/webgl', 'fast/canvas/webgl', 'animations/3d', 'webgl', 'mhtml', 'http/tests/canvas/webgl', 'fast/css/variables', 'inspector/styles/variables'])
+ expected_directories = set(['mathml', 'compositing/webgl', 'fast/canvas/webgl', 'webgl', 'mhtml', 'http/tests/canvas/webgl', 'fast/css/variables', 'inspector/styles/variables'])
result_directories = set(TestWebKitPort(symbols_string=symbols_string)._skipped_tests_for_unsupported_features(test_list=['mathml/foo.html']))
self.assertEqual(result_directories, expected_directories)
@@ -513,9 +498,6 @@
port = TestWebKitPort(port_name="testwebkitport-version")
self.assertEqual(platform_dirs(port), ['LayoutTests', 'testwebkitport', 'testwebkitport-version'])
- port = TestWebKitPort(port_name="testwebkitport-version-wk2")
- self.assertEqual(platform_dirs(port), ['LayoutTests', 'testwebkitport', 'testwebkitport-version', 'wk2', 'testwebkitport-wk2'])
-
port = TestWebKitPort(port_name="testwebkitport-version",
options=MockOptions(additional_platform_directory=["internal-testwebkitport"]))
self.assertEqual(platform_dirs(port), ['LayoutTests', 'testwebkitport', 'testwebkitport-version', 'internal-testwebkitport'])
@@ -533,40 +515,6 @@
port = TestWebKitPort(host=host)
self.assertEqual(''.join(port.expectations_dict().values()), 'BUG_TESTEXPECTATIONS SKIP : fast/html/article-element.html = FAIL\n')
- def test_build_driver(self):
- output = OutputCapture()
- port = TestWebKitPort()
- # Delay setting _executive to avoid logging during construction
- port._executive = MockExecutive(should_log=True)
- port._options = MockOptions(configuration="Release") # This should not be necessary, but I think TestWebKitPort is actually reading from disk (and thus detects the current configuration).
- expected_logs = "MOCK run_command: ['Tools/Scripts/build-dumprendertree', '--release'], cwd=/mock-checkout, env={'LC_ALL': 'C', 'MOCK_ENVIRON_COPY': '1'}\n"
- self.assertTrue(output.assert_outputs(self, port._build_driver, expected_logs=expected_logs))
-
- # Make sure when passed --webkit-test-runner we build the right tool.
- port._options = MockOptions(webkit_test_runner=True, configuration="Release")
- expected_logs = "MOCK run_command: ['Tools/Scripts/build-dumprendertree', '--release'], cwd=/mock-checkout, env={'LC_ALL': 'C', 'MOCK_ENVIRON_COPY': '1'}\nMOCK run_command: ['Tools/Scripts/build-webkittestrunner', '--release'], cwd=/mock-checkout, env={'LC_ALL': 'C', 'MOCK_ENVIRON_COPY': '1'}\n"
- self.assertTrue(output.assert_outputs(self, port._build_driver, expected_logs=expected_logs))
-
- # Make sure we show the build log when --verbose is passed, which we simulate by setting the logging level to DEBUG.
- output.set_log_level(logging.DEBUG)
- port._options = MockOptions(configuration="Release")
- expected_logs = """MOCK run_command: ['Tools/Scripts/build-dumprendertree', '--release'], cwd=/mock-checkout, env={'LC_ALL': 'C', 'MOCK_ENVIRON_COPY': '1'}
-Output of ['Tools/Scripts/build-dumprendertree', '--release']:
-MOCK output of child process
-"""
- self.assertTrue(output.assert_outputs(self, port._build_driver, expected_logs=expected_logs))
- output.set_log_level(logging.INFO)
-
- # Make sure that failure to build returns False.
- port._executive = MockExecutive(should_log=True, should_throw=True)
- # Because WK2 currently has to build both webkittestrunner and DRT, if DRT fails, that's the only one it tries.
- expected_logs = """MOCK run_command: ['Tools/Scripts/build-dumprendertree', '--release'], cwd=/mock-checkout, env={'LC_ALL': 'C', 'MOCK_ENVIRON_COPY': '1'}
-MOCK ScriptError
-
-MOCK output of child process
-"""
- self.assertFalse(output.assert_outputs(self, port._build_driver, expected_logs=expected_logs))
-
def _assert_config_file_for_platform(self, port, platform, config_file):
self.assertEqual(port._apache_config_file_name_for_platform(platform), config_file)
@@ -627,30 +575,6 @@
finally:
os.environ = saved_environ.copy()
- def test_check_build(self):
- port = self.make_port(options=MockOptions(build=True))
- self.build_called = False
-
- def build_driver_called():
- self.build_called = True
- return True
-
- port._build_driver = build_driver_called
- port.check_build(False)
- self.assertTrue(self.build_called)
-
- port = self.make_port(options=MockOptions(root='/tmp', build=True))
- self.build_called = False
- port._build_driver = build_driver_called
- port.check_build(False)
- self.assertFalse(self.build_called, None)
-
- port = self.make_port(options=MockOptions(build=False))
- self.build_called = False
- port._build_driver = build_driver_called
- port.check_build(False)
- self.assertFalse(self.build_called, None)
-
def test_additional_platform_directory(self):
port = self.make_port(options=MockOptions(additional_platform_directory=['/tmp/foo']))
self.assertEqual(port.baseline_search_path()[0], '/tmp/foo')
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/pulseaudio_sanitizer.py b/Tools/Scripts/webkitpy/layout_tests/port/pulseaudio_sanitizer.py
deleted file mode 100644
index 465b921..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/pulseaudio_sanitizer.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-# Copyrigth (C) 2012 Intel Corporation
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the Google name nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import logging
-import os
-import subprocess
-
-
-_log = logging.getLogger(__name__)
-
-
-# Shared by GTK and EFL for pulseaudio sanitizing before running tests.
-class PulseAudioSanitizer:
- def unload_pulseaudio_module(self):
- # Unload pulseaudio's module-stream-restore, since it remembers
- # volume settings from different runs, and could affect
- # multimedia tests results
- self._pa_module_index = -1
- with open(os.devnull, 'w') as devnull:
- try:
- pactl_process = subprocess.Popen(["pactl", "list", "short", "modules"], stdout=subprocess.PIPE, stderr=devnull)
- pactl_process.wait()
- except OSError:
- # pactl might not be available.
- _log.debug('pactl not found. Please install pulseaudio-utils to avoid some potential media test failures.')
- return
- modules_list = pactl_process.communicate()[0]
- for module in modules_list.splitlines():
- if module.find("module-stream-restore") >= 0:
- # Some pulseaudio-utils versions don't provide
- # the index, just an empty string
- self._pa_module_index = module.split('\t')[0] or -1
- try:
- # Since they could provide other stuff (not an index
- # nor an empty string, let's make sure this is an int.
- if int(self._pa_module_index) != -1:
- pactl_process = subprocess.Popen(["pactl", "unload-module", self._pa_module_index])
- pactl_process.wait()
- if pactl_process.returncode == 0:
- _log.debug('Unloaded module-stream-restore successfully')
- else:
- _log.debug('Unloading module-stream-restore failed')
- except ValueError:
- # pactl should have returned an index if the module is found
- _log.debug('Unable to parse module index. Please check if your pulseaudio-utils version is too old.')
- return
-
- def restore_pulseaudio_module(self):
- # If pulseaudio's module-stream-restore was previously unloaded,
- # restore it back. We shouldn't need extra checks here, since an
- # index != -1 here means we successfully unloaded it previously.
- if self._pa_module_index != -1:
- with open(os.devnull, 'w') as devnull:
- pactl_process = subprocess.Popen(["pactl", "load-module", "module-stream-restore"], stdout=devnull, stderr=devnull)
- pactl_process.wait()
- if pactl_process.returncode == 0:
- _log.debug('Restored module-stream-restore successfully')
- else:
- _log.debug('Restoring module-stream-restore failed')
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/pulseaudio_sanitizer_mock.py b/Tools/Scripts/webkitpy/layout_tests/port/pulseaudio_sanitizer_mock.py
deleted file mode 100644
index 88a962a..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/pulseaudio_sanitizer_mock.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyrigth (C) 2013 Zan Dobersek <zandobersek@gmail.com>
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the Google name nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-class PulseAudioSanitizerMock:
- def unload_pulseaudio_module(self):
- pass
-
- def restore_pulseaudio_module(self):
- pass
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/qt.py b/Tools/Scripts/webkitpy/layout_tests/port/qt.py
deleted file mode 100644
index 4840725..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/qt.py
+++ /dev/null
@@ -1,192 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the Google name nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""QtWebKit implementation of the Port interface."""
-
-import glob
-import logging
-import re
-import sys
-import os
-
-from webkitpy.common.memoized import memoized
-from webkitpy.layout_tests.models.test_configuration import TestConfiguration
-from webkitpy.layout_tests.port.base import Port
-from webkitpy.layout_tests.port.xvfbdriver import XvfbDriver
-
-_log = logging.getLogger(__name__)
-
-
-class QtPort(Port):
- ALL_VERSIONS = ['linux', 'win', 'mac']
- port_name = "qt"
-
- def _wk2_port_name(self):
- return "qt-5.0-wk2"
-
- def _port_flag_for_scripts(self):
- return "--qt"
-
- @classmethod
- def determine_full_port_name(cls, host, options, port_name):
- if port_name and port_name != cls.port_name:
- return port_name
- return port_name + '-' + host.platform.os_name
-
- # sys_platform exists only for unit testing.
- def __init__(self, host, port_name, **kwargs):
- super(QtPort, self).__init__(host, port_name, **kwargs)
-
- # FIXME: This will allow Port.baseline_search_path
- # to do the right thing, but doesn't include support for qt-4.8 or qt-arm (seen in LayoutTests/platform) yet.
- self._operating_system = port_name.replace('qt-', '')
-
- # FIXME: Why is this being set at all?
- self._version = self.operating_system()
-
- def _generate_all_test_configurations(self):
- configurations = []
- for version in self.ALL_VERSIONS:
- for build_type in self.ALL_BUILD_TYPES:
- configurations.append(TestConfiguration(version=version, architecture='x86', build_type=build_type))
- return configurations
-
- def _build_driver(self):
- # The Qt port builds DRT as part of the main build step
- return True
-
- def supports_per_test_timeout(self):
- return True
-
- def _path_to_driver(self):
- return self._build_path('bin/%s' % self.driver_name())
-
- def _path_to_image_diff(self):
- return self._build_path('bin/ImageDiff')
-
- def _path_to_webcore_library(self):
- if self.operating_system() == 'mac':
- return self._build_path('lib/QtWebKitWidgets.framework/QtWebKitWidgets')
- else:
- return self._build_path('lib/libQt5WebKitWidgets.so')
-
- def _modules_to_search_for_symbols(self):
- # We search in every library to be reliable in the case of building with CONFIG+=force_static_libs_as_shared.
- if self.operating_system() == 'mac':
- frameworks = glob.glob(os.path.join(self._build_path('lib'), '*.framework'))
- return [os.path.join(framework, os.path.splitext(os.path.basename(framework))[0]) for framework in frameworks]
- else:
- suffix = 'dll' if self.operating_system() == 'win' else 'so'
- return glob.glob(os.path.join(self._build_path('lib'), 'lib*.' + suffix))
-
- @memoized
- def qt_version(self):
- version = ''
- try:
- for line in self._executive.run_command(['qmake', '-v']).split('\n'):
- match = re.search('Qt\sversion\s(?P<version>\d\.\d)', line)
- if match:
- version = match.group('version')
- break
- except OSError:
- version = '4.8'
- return version
-
- def _search_paths(self):
- # qt-5.0-mac-wk2
- # /
- # qt-5.0-wk1 qt-5.0-wk2
- # \/
- # qt-5.0
- # \
- # (qt-linux|qt-mac|qt-win)
- # |
- # qt
- search_paths = []
- version = self.qt_version()
- if '5.0' in version:
- if self.get_option('webkit_test_runner'):
- if self.operating_system() == 'mac':
- search_paths.append('qt-5.0-mac-wk2')
- search_paths.append('qt-5.0-wk2')
- else:
- search_paths.append('qt-5.0-wk1')
- search_paths.append('qt-5.0')
-
- search_paths.append(self.port_name + '-' + self.operating_system())
- search_paths.append(self.port_name)
- return search_paths
-
- def default_baseline_search_path(self):
- return map(self._webkit_baseline_path, self._search_paths())
-
- def _port_specific_expectations_files(self):
- paths = self._search_paths()
- if self.get_option('webkit_test_runner'):
- paths.append('wk2')
-
- # expectations_files() uses the directories listed in _search_paths reversed.
- # e.g. qt -> qt-linux -> qt-5.0 -> qt-5.0-wk1
- return list(reversed([self._filesystem.join(self._webkit_baseline_path(p), 'TestExpectations') for p in paths]))
-
- def setup_environ_for_server(self, server_name=None):
- clean_env = super(QtPort, self).setup_environ_for_server(server_name)
- clean_env['QTWEBKIT_PLUGIN_PATH'] = self._build_path('lib/plugins')
- self._copy_value_from_environ_if_set(clean_env, 'QT_DRT_WEBVIEW_MODE')
- self._copy_value_from_environ_if_set(clean_env, 'DYLD_IMAGE_SUFFIX')
- self._copy_value_from_environ_if_set(clean_env, 'QT_WEBKIT_LOG')
- self._copy_value_from_environ_if_set(clean_env, 'DISABLE_NI_WARNING')
- self._copy_value_from_environ_if_set(clean_env, 'QT_WEBKIT_PAUSE_UI_PROCESS')
- self._copy_value_from_environ_if_set(clean_env, 'QT_QPA_PLATFORM_PLUGIN_PATH')
- self._copy_value_from_environ_if_set(clean_env, 'QT_WEBKIT_DISABLE_UIPROCESS_DUMPPIXELS')
- return clean_env
-
- # FIXME: We should find a way to share this implmentation with Gtk,
- # or teach run-launcher how to call run-safari and move this down to Port.
- def show_results_html_file(self, results_filename):
- run_launcher_args = []
- if self.get_option('webkit_test_runner'):
- run_launcher_args.append('-2')
- run_launcher_args.append("file://%s" % results_filename)
- self._run_script("run-launcher", run_launcher_args)
-
- def operating_system(self):
- return self._operating_system
-
- def check_sys_deps(self, needs_http):
- result = super(QtPort, self).check_sys_deps(needs_http)
- if not 'WEBKIT_TESTFONTS' in os.environ:
- _log.error('\nThe WEBKIT_TESTFONTS environment variable is not defined or not set properly.')
- _log.error('You must set it before running the tests.')
- _log.error('Use git to grab the actual fonts from http://gitorious.org/qtwebkit/testfonts')
- return False
- return result
-
- # Qt port is not ready for parallel testing, see https://bugs.webkit.org/show_bug.cgi?id=77730 for details.
- def default_child_processes(self):
- return 1
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/qt_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/qt_unittest.py
deleted file mode 100644
index 2adfbc1..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/qt_unittest.py
+++ /dev/null
@@ -1,123 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest2 as unittest
-import os
-from copy import deepcopy
-
-from webkitpy.common.system.executive_mock import MockExecutive, MockExecutive2
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.common.system.systemhost_mock import MockSystemHost
-from webkitpy.layout_tests.port import port_testcase
-from webkitpy.layout_tests.port.qt import QtPort
-from webkitpy.tool.mocktool import MockOptions
-
-
-class QtPortTest(port_testcase.PortTestCase):
- port_name = 'qt-mac'
- port_maker = QtPort
- search_paths_cases = [
- {'search_paths':['qt-5.0-mac-wk2', 'qt-5.0-wk2', 'qt-5.0', 'qt-mac', 'qt'], 'os_name':'mac', 'use_webkit2':True, 'qt_version':'5.0'},
- {'search_paths':['qt-5.0-wk2', 'qt-5.0', 'qt-win', 'qt'], 'os_name':'win', 'use_webkit2':True, 'qt_version':'5.0'},
- {'search_paths':['qt-5.0-wk2', 'qt-5.0', 'qt-linux', 'qt'], 'os_name':'linux', 'use_webkit2':True, 'qt_version':'5.0'},
-
- {'search_paths':['qt-5.0-wk1', 'qt-5.0', 'qt-mac', 'qt'], 'os_name':'mac', 'use_webkit2':False, 'qt_version':'5.0'},
- {'search_paths':['qt-5.0-wk1', 'qt-5.0', 'qt-win', 'qt'], 'os_name':'win', 'use_webkit2':False, 'qt_version':'5.0'},
- {'search_paths':['qt-5.0-wk1', 'qt-5.0', 'qt-linux', 'qt'], 'os_name':'linux', 'use_webkit2':False, 'qt_version':'5.0'},
- ]
-
- def _assert_search_path(self, search_paths, os_name, use_webkit2=False, qt_version='5.0'):
- # FIXME: Port constructors should not "parse" the port name, but
- # rather be passed components (directly or via setters). Once
- # we fix that, this method will need a re-write.
- host = MockSystemHost(os_name=os_name)
- host.executive = MockExecutive2(self._qt_version(qt_version))
- port_name = 'qt-' + os_name
- port = self.make_port(host=host, qt_version=qt_version, port_name=port_name,
- options=MockOptions(webkit_test_runner=use_webkit2, platform='qt'))
- absolute_search_paths = map(port._webkit_baseline_path, search_paths)
- self.assertEqual(port.baseline_search_path(), absolute_search_paths)
-
- def _assert_expectations_files(self, search_paths, os_name, use_webkit2=False, qt_version='5.0'):
- # FIXME: Port constructors should not "parse" the port name, but
- # rather be passed components (directly or via setters). Once
- # we fix that, this method will need a re-write.
- host = MockSystemHost(os_name=os_name)
- host.executive = MockExecutive2(self._qt_version(qt_version))
- port_name = 'qt-' + os_name
- port = self.make_port(host=host, qt_version=qt_version, port_name=port_name,
- options=MockOptions(webkit_test_runner=use_webkit2, platform='qt'))
- self.assertEqual(port.expectations_files(), search_paths)
-
- def _qt_version(self, qt_version):
- if qt_version in '5.0':
- return 'QMake version 2.01a\nUsing Qt version 5.0.0 in /usr/local/Trolltech/Qt-5.0.0/lib'
-
- def test_baseline_search_path(self):
- for case in self.search_paths_cases:
- self._assert_search_path(**case)
-
- def test_expectations_files(self):
- for case in self.search_paths_cases:
- expectations_case = deepcopy(case)
- if expectations_case['use_webkit2']:
- expectations_case['search_paths'].append("wk2")
- expectations_case['search_paths'].append('')
- expectations_case['search_paths'].reverse()
- expectations_case['search_paths'] = map(lambda path: '/mock-checkout/LayoutTests/TestExpectations' if not path else '/mock-checkout/LayoutTests/platform/%s/TestExpectations' % (path), expectations_case['search_paths'])
- self._assert_expectations_files(**expectations_case)
-
- def test_show_results_html_file(self):
- port = self.make_port()
- port._executive = MockExecutive(should_log=True)
- expected_logs = "MOCK run_command: ['Tools/Scripts/run-launcher', '--release', '--qt', 'file://test.html'], cwd=/mock-checkout\n"
- OutputCapture().assert_outputs(self, port.show_results_html_file, ["test.html"], expected_logs=expected_logs)
-
- def test_setup_environ_for_server(self):
- port = self.make_port()
- env = port.setup_environ_for_server(port.driver_name())
- self.assertEqual(env['QTWEBKIT_PLUGIN_PATH'], '/mock-build/lib/plugins')
-
- def test_operating_system(self):
- self.assertEqual('linux', self.make_port(port_name='qt-linux', os_name='linux').operating_system())
- self.assertEqual('mac', self.make_port(os_name='mac').operating_system())
- self.assertEqual('win', self.make_port(port_name='qt-win', os_name='win').operating_system())
-
- def test_check_sys_deps(self):
- port = self.make_port()
-
- # Success
- os.environ['WEBKIT_TESTFONTS'] = '/tmp/foo'
- port._executive = MockExecutive2(exit_code=0)
- self.assertTrue(port.check_sys_deps(needs_http=False))
-
- # Failure
- del os.environ['WEBKIT_TESTFONTS']
- port._executive = MockExecutive2(exit_code=1,
- output='testing output failure')
- self.assertFalse(port.check_sys_deps(needs_http=False))
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test.py b/Tools/Scripts/webkitpy/layout_tests/port/test.py
index c622cc2..b7f633c 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/test.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/test.py
@@ -366,7 +366,7 @@
Port.__init__(self, host, port_name or TestPort.default_port_name, **kwargs)
self._tests = unit_test_list()
self._flakes = set()
- self._expectations_path = LAYOUT_TEST_DIR + '/platform/test/TestExpectations'
+ self._generic_expectations_path = LAYOUT_TEST_DIR + '/TestExpectations'
self._results_directory = None
self._operating_system = 'mac'
@@ -385,6 +385,9 @@
}
self._version = version_map[self._name]
+ def buildbot_archives_baselines(self):
+ return self._name != 'test-win-xp'
+
def default_pixel_tests(self):
return True
@@ -400,7 +403,7 @@
'test-win-win7': ['test-win-win7'],
'test-win-vista': ['test-win-vista', 'test-win-win7'],
'test-win-xp': ['test-win-xp', 'test-win-vista', 'test-win-win7'],
- 'test-linux-x86_64': ['test-linux', 'test-win-win7'],
+ 'test-linux-x86_64': ['test-linux-x86_64', 'test-win-win7'],
}
return [self._webkit_baseline_path(d) for d in search_paths[self.name()]]
@@ -496,8 +499,8 @@
def _path_to_apache_config_file(self):
return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', 'httpd.conf')
- def path_to_test_expectations_file(self):
- return self._expectations_path
+ def path_to_generic_test_expectations_file(self):
+ return self._generic_expectations_path
def all_test_configurations(self):
"""Returns a sequence of the TestConfigurations the port supports."""
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/win.py b/Tools/Scripts/webkitpy/layout_tests/port/win.py
deleted file mode 100644
index 6adbf75..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/win.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the Google name nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import logging
-import re
-import sys
-
-from webkitpy.common.system.systemhost import SystemHost
-from webkitpy.common.system.executive import ScriptError, Executive
-from webkitpy.common.system.path import abspath_to_uri
-from webkitpy.layout_tests.port.apple import ApplePort
-
-
-_log = logging.getLogger(__name__)
-
-
-class WinPort(ApplePort):
- port_name = "win"
-
- VERSION_FALLBACK_ORDER = ["win-xp", "win-vista", "win-7sp0", "win-win7"]
-
- ARCHITECTURES = ['x86']
-
- def do_text_results_differ(self, expected_text, actual_text):
- # Sanity was restored in WK2, so we don't need this hack there.
- if self.get_option('webkit_test_runner'):
- return ApplePort.do_text_results_differ(self, expected_text, actual_text)
-
- # This is a hack (which dates back to ORWT).
- # Windows does not have an EDITING DELEGATE, so we strip any EDITING DELEGATE
- # messages to make more of the tests pass.
- # It's possible more of the ports might want this and this could move down into WebKitPort.
- delegate_regexp = re.compile("^EDITING DELEGATE: .*?\n", re.MULTILINE)
- expected_text = delegate_regexp.sub("", expected_text)
- actual_text = delegate_regexp.sub("", actual_text)
- return expected_text != actual_text
-
- def default_baseline_search_path(self):
- name = self._name.replace('-wk2', '')
- if name.endswith(self.FUTURE_VERSION):
- fallback_names = [self.port_name]
- else:
- fallback_names = self.VERSION_FALLBACK_ORDER[self.VERSION_FALLBACK_ORDER.index(name):-1] + [self.port_name]
- # FIXME: The AppleWin port falls back to AppleMac for some results. Eventually we'll have a shared 'apple' port.
- if self.get_option('webkit_test_runner'):
- fallback_names.insert(0, 'win-wk2')
- fallback_names.append('mac-wk2')
- # Note we do not add 'wk2' here, even though it's included in _skipped_search_paths().
- # FIXME: Perhaps we should get this list from MacPort?
- fallback_names.extend(['mac-lion', 'mac'])
- return map(self._webkit_baseline_path, fallback_names)
-
- def operating_system(self):
- return 'win'
-
- def show_results_html_file(self, results_filename):
- self._run_script('run-safari', [abspath_to_uri(SystemHost().platform, results_filename)])
-
- # FIXME: webkitperl/httpd.pm installs /usr/lib/apache/libphp4.dll on cycwin automatically
- # as part of running old-run-webkit-tests. That's bad design, but we may need some similar hack.
- # We might use setup_environ_for_server for such a hack (or modify apache_http_server.py).
-
- def _runtime_feature_list(self):
- supported_features_command = [self._path_to_driver(), '--print-supported-features']
- try:
- output = self._executive.run_command(supported_features_command, error_handler=Executive.ignore_error)
- except OSError, e:
- _log.warn("Exception running driver: %s, %s. Driver must be built before calling WebKitPort.test_expectations()." % (supported_features_command, e))
- return None
-
- # Note: win/DumpRenderTree.cpp does not print a leading space before the features_string.
- match_object = re.match("SupportedFeatures:\s*(?P<features_string>.*)\s*", output)
- if not match_object:
- return None
- return match_object.group('features_string').split(' ')
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/win_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/win_unittest.py
deleted file mode 100644
index e77687c..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/win_unittest.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# Copyright (C) 2011 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import StringIO
-import unittest2 as unittest
-
-from webkitpy.common.system.executive import ScriptError
-from webkitpy.common.system.executive_mock import MockExecutive, MockExecutive2
-from webkitpy.common.system.filesystem_mock import MockFileSystem
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.common.system.systemhost_mock import MockSystemHost
-from webkitpy.layout_tests.port import port_testcase
-from webkitpy.layout_tests.port.win import WinPort
-from webkitpy.tool.mocktool import MockOptions
-
-
-class WinPortTest(port_testcase.PortTestCase):
- os_name = 'win'
- os_version = 'xp'
- port_name = 'win-xp'
- port_maker = WinPort
-
- def test_show_results_html_file(self):
- port = self.make_port()
- port._executive = MockExecutive(should_log=True)
- capture = OutputCapture()
- capture.capture_output()
- port.show_results_html_file('test.html')
- _, _, logs = capture.restore_output()
- # We can't know for sure what path will be produced by cygpath, but we can assert about
- # everything else.
- self.assertTrue(logs.startswith("MOCK run_command: ['Tools/Scripts/run-safari', '--release', '"))
- self.assertTrue(logs.endswith("test.html'], cwd=/mock-checkout\n"))
-
- def _assert_search_path(self, expected_search_paths, version, use_webkit2=False):
- port = self.make_port(port_name='win', os_version=version, options=MockOptions(webkit_test_runner=use_webkit2))
- absolute_search_paths = map(port._webkit_baseline_path, expected_search_paths)
- self.assertEqual(port.baseline_search_path(), absolute_search_paths)
-
- def test_baseline_search_path(self):
- self._assert_search_path(['win-xp', 'win-vista', 'win-7sp0', 'win', 'mac-lion', 'mac'], 'xp')
- self._assert_search_path(['win-vista', 'win-7sp0', 'win', 'mac-lion', 'mac'], 'vista')
- self._assert_search_path(['win-7sp0', 'win', 'mac-lion', 'mac'], '7sp0')
-
- self._assert_search_path(['win-wk2', 'win-xp', 'win-vista', 'win-7sp0', 'win', 'mac-wk2', 'mac-lion', 'mac'], 'xp', use_webkit2=True)
- self._assert_search_path(['win-wk2', 'win-vista', 'win-7sp0', 'win', 'mac-wk2', 'mac-lion', 'mac'], 'vista', use_webkit2=True)
- self._assert_search_path(['win-wk2', 'win-7sp0', 'win', 'mac-wk2', 'mac-lion', 'mac'], '7sp0', use_webkit2=True)
-
- def _assert_version(self, port_name, expected_version):
- host = MockSystemHost(os_name='win', os_version=expected_version)
- port = WinPort(host, port_name=port_name)
- self.assertEqual(port.version(), expected_version)
-
- def test_versions(self):
- self._assert_version('win-xp', 'xp')
- self._assert_version('win-vista', 'vista')
- self._assert_version('win-7sp0', '7sp0')
- self.assertRaises(AssertionError, self._assert_version, 'win-me', 'xp')
-
- def test_compare_text(self):
- expected = "EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\nfoo\nEDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n"
- port = self.make_port()
- self.assertFalse(port.do_text_results_differ(expected, "foo\n"))
- self.assertTrue(port.do_text_results_differ(expected, "foo"))
- self.assertTrue(port.do_text_results_differ(expected, "bar"))
-
- # This hack doesn't exist in WK2.
- port._options = MockOptions(webkit_test_runner=True)
- self.assertTrue(port.do_text_results_differ(expected, "foo\n"))
-
- def test_operating_system(self):
- self.assertEqual('win', self.make_port().operating_system())
-
- def test_runtime_feature_list(self):
- port = self.make_port()
- port._executive.run_command = lambda command, cwd=None, error_handler=None: "Nonsense"
- # runtime_features_list returns None when its results are meaningless (it couldn't run DRT or parse the output, etc.)
- self.assertEqual(port._runtime_feature_list(), None)
- port._executive.run_command = lambda command, cwd=None, error_handler=None: "SupportedFeatures:foo bar"
- self.assertEqual(port._runtime_feature_list(), ['foo', 'bar'])
-
- def test_expectations_files(self):
- self.assertEqual(len(self.make_port().expectations_files()), 3)
- self.assertEqual(len(self.make_port(options=MockOptions(webkit_test_runner=True, configuration='Release')).expectations_files()), 5)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/xvfbdriver.py b/Tools/Scripts/webkitpy/layout_tests/port/xvfbdriver.py
deleted file mode 100644
index 71ea8dd..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/xvfbdriver.py
+++ /dev/null
@@ -1,113 +0,0 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the Google name nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import logging
-import os
-import re
-import time
-
-from webkitpy.layout_tests.port.server_process import ServerProcess
-from webkitpy.layout_tests.port.driver import Driver
-from webkitpy.common.system.file_lock import FileLock
-
-_log = logging.getLogger(__name__)
-
-
-class XvfbDriver(Driver):
- @staticmethod
- def check_xvfb(port):
- xvfb_found = port.host.executive.run_command(['which', 'Xvfb'], return_exit_code=True) is 0
- if not xvfb_found:
- _log.error("No Xvfb found. Cannot run layout tests.")
- return xvfb_found
-
- def __init__(self, *args, **kwargs):
- Driver.__init__(self, *args, **kwargs)
- self._guard_lock = None
- self._startup_delay_secs = 1.0
-
- def _next_free_display(self):
- running_pids = self._port.host.executive.run_command(['ps', '-eo', 'comm,command'])
- reserved_screens = set()
- for pid in running_pids.split('\n'):
- match = re.match('(X|Xvfb|Xorg)\s+.*\s:(?P<screen_number>\d+)', pid)
- if match:
- reserved_screens.add(int(match.group('screen_number')))
- for i in range(99):
- if i not in reserved_screens:
- _guard_lock_file = self._port.host.filesystem.join('/tmp', 'WebKitXvfb.lock.%i' % i)
- self._guard_lock = self._port.host.make_file_lock(_guard_lock_file)
- if self._guard_lock.acquire_lock():
- return i
-
- def _start(self, pixel_tests, per_test_args):
- self.stop()
-
- # Use even displays for pixel tests and odd ones otherwise. When pixel tests are disabled,
- # DriverProxy creates two drivers, one for normal and the other for ref tests. Both have
- # the same worker number, so this prevents them from using the same Xvfb instance.
- display_id = self._next_free_display()
- self._lock_file = "/tmp/.X%d-lock" % display_id
-
- run_xvfb = ["Xvfb", ":%d" % display_id, "-screen", "0", "800x600x24", "-nolisten", "tcp"]
- with open(os.devnull, 'w') as devnull:
- self._xvfb_process = self._port.host.executive.popen(run_xvfb, stderr=devnull)
-
- # Crashes intend to occur occasionally in the first few tests that are run through each
- # worker because the Xvfb display isn't ready yet. Halting execution a bit should avoid that.
- time.sleep(self._startup_delay_secs)
-
- server_name = self._port.driver_name()
- environment = self._port.setup_environ_for_server(server_name)
- # We must do this here because the DISPLAY number depends on _worker_number
- environment['DISPLAY'] = ":%d" % display_id
- self._driver_tempdir = self._port._filesystem.mkdtemp(prefix='%s-' % self._port.driver_name())
- environment['DUMPRENDERTREE_TEMP'] = str(self._driver_tempdir)
- environment['LOCAL_RESOURCE_ROOT'] = self._port.layout_tests_dir()
-
- # Currently on WebKit2, there is no API for setting the application
- # cache directory. Each worker should have it's own and it should be
- # cleaned afterwards, so we set it to inside the temporary folder by
- # prepending XDG_CACHE_HOME with DUMPRENDERTREE_TEMP.
- environment['XDG_CACHE_HOME'] = self._port.host.filesystem.join(str(self._driver_tempdir), 'appcache')
-
- self._crashed_process_name = None
- self._crashed_pid = None
- self._server_process = self._port._server_process_constructor(self._port, server_name, self.cmd_line(pixel_tests, per_test_args), environment)
- self._server_process.start()
-
- def stop(self):
- super(XvfbDriver, self).stop()
- if self._guard_lock:
- self._guard_lock.release_lock()
- self._guard_lock = None
- if getattr(self, '_xvfb_process', None):
- self._port.host.executive.kill_process(self._xvfb_process.pid)
- self._xvfb_process = None
- if self._port.host.filesystem.exists(self._lock_file):
- self._port.host.filesystem.remove(self._lock_file)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/xvfbdriver_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/xvfbdriver_unittest.py
deleted file mode 100644
index 4c5d338..0000000
--- a/Tools/Scripts/webkitpy/layout_tests/port/xvfbdriver_unittest.py
+++ /dev/null
@@ -1,135 +0,0 @@
-# Copyright (C) 2012 Zan Dobersek <zandobersek@gmail.com>
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import logging
-import unittest2 as unittest
-
-from webkitpy.common.system.filesystem_mock import MockFileSystem
-from webkitpy.common.system.executive_mock import MockExecutive2
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.common.system.systemhost_mock import MockSystemHost
-from webkitpy.layout_tests.port import Port
-from webkitpy.layout_tests.port.server_process_mock import MockServerProcess
-from webkitpy.layout_tests.port.xvfbdriver import XvfbDriver
-from webkitpy.tool.mocktool import MockOptions
-
-_log = logging.getLogger(__name__)
-
-
-class XvfbDriverTest(unittest.TestCase):
- def make_driver(self, worker_number=0, xorg_running=False, executive=None):
- port = Port(MockSystemHost(log_executive=True, executive=executive), 'xvfbdrivertestport', options=MockOptions(configuration='Release'))
- port._config.build_directory = lambda configuration: "/mock-build"
- port._server_process_constructor = MockServerProcess
- if xorg_running:
- port._executive._running_pids['Xorg'] = 108
-
- driver = XvfbDriver(port, worker_number=worker_number, pixel_tests=True)
- driver._startup_delay_secs = 0
- return driver
-
- def cleanup_driver(self, driver):
- # Setting _xvfb_process member to None is necessary as the Driver object is stopped on deletion,
- # killing the Xvfb process if present. Thus, this method should only be called from tests that do not
- # intend to test the behavior of XvfbDriver.stop.
- driver._xvfb_process = None
-
- def assertDriverStartSuccessful(self, driver, expected_logs, expected_display, pixel_tests=False):
- OutputCapture().assert_outputs(self, driver.start, [pixel_tests, []], expected_logs=expected_logs)
- self.assertTrue(driver._server_process.started)
- self.assertEqual(driver._server_process.env["DISPLAY"], expected_display)
-
- def test_start_no_pixel_tests(self):
- driver = self.make_driver()
- expected_logs = "MOCK run_command: ['ps', '-eo', 'comm,command'], cwd=None\nMOCK popen: ['Xvfb', ':0', '-screen', '0', '800x600x24', '-nolisten', 'tcp']\n"
- self.assertDriverStartSuccessful(driver, expected_logs=expected_logs, expected_display=":0")
- self.cleanup_driver(driver)
-
- def test_start_pixel_tests(self):
- driver = self.make_driver()
- expected_logs = "MOCK run_command: ['ps', '-eo', 'comm,command'], cwd=None\nMOCK popen: ['Xvfb', ':0', '-screen', '0', '800x600x24', '-nolisten', 'tcp']\n"
- self.assertDriverStartSuccessful(driver, expected_logs=expected_logs, expected_display=":0", pixel_tests=True)
- self.cleanup_driver(driver)
-
- def test_start_arbitrary_worker_number(self):
- driver = self.make_driver(worker_number=17)
- expected_logs = "MOCK run_command: ['ps', '-eo', 'comm,command'], cwd=None\nMOCK popen: ['Xvfb', ':0', '-screen', '0', '800x600x24', '-nolisten', 'tcp']\n"
- self.assertDriverStartSuccessful(driver, expected_logs=expected_logs, expected_display=":0", pixel_tests=True)
- self.cleanup_driver(driver)
-
- def test_next_free_display(self):
- output = "Xorg /usr/bin/X :0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch -background none\nXvfb Xvfb :1 -screen 0 800x600x24 -nolisten tcp"
- executive = MockExecutive2(output)
- driver = self.make_driver(executive=executive)
- self.assertEqual(driver._next_free_display(), 2)
- self.cleanup_driver(driver)
- output = "X /usr/bin/X :0 vt7 -nolisten tcp -auth /var/run/xauth/A:0-8p7Ybb"
- executive = MockExecutive2(output)
- driver = self.make_driver(executive=executive)
- self.assertEqual(driver._next_free_display(), 1)
- self.cleanup_driver(driver)
- output = "Xvfb Xvfb :0 -screen 0 800x600x24 -nolisten tcp"
- executive = MockExecutive2(output)
- driver = self.make_driver(executive=executive)
- self.assertEqual(driver._next_free_display(), 1)
- self.cleanup_driver(driver)
- output = "Xvfb Xvfb :1 -screen 0 800x600x24 -nolisten tcp\nXvfb Xvfb :0 -screen 0 800x600x24 -nolisten tcp\nXvfb Xvfb :3 -screen 0 800x600x24 -nolisten tcp"
- executive = MockExecutive2(output)
- driver = self.make_driver(executive=executive)
- self.assertEqual(driver._next_free_display(), 2)
- self.cleanup_driver(driver)
-
- def test_start_next_worker(self):
- driver = self.make_driver()
- driver._next_free_display = lambda: 0
- expected_logs = "MOCK popen: ['Xvfb', ':0', '-screen', '0', '800x600x24', '-nolisten', 'tcp']\n"
- self.assertDriverStartSuccessful(driver, expected_logs=expected_logs, expected_display=":0", pixel_tests=True)
- self.cleanup_driver(driver)
- driver = self.make_driver()
- driver._next_free_display = lambda: 3
- expected_logs = "MOCK popen: ['Xvfb', ':3', '-screen', '0', '800x600x24', '-nolisten', 'tcp']\n"
- self.assertDriverStartSuccessful(driver, expected_logs=expected_logs, expected_display=":3", pixel_tests=True)
- self.cleanup_driver(driver)
-
- def test_stop(self):
- filesystem = MockFileSystem(files={'/tmp/.X42-lock': '1234\n'})
- port = Port(MockSystemHost(log_executive=True, filesystem=filesystem), 'xvfbdrivertestport', options=MockOptions(configuration='Release'))
- port._executive.kill_process = lambda x: _log.info("MOCK kill_process pid: " + str(x))
- driver = XvfbDriver(port, worker_number=0, pixel_tests=True)
-
- class FakeXvfbProcess(object):
- pid = 1234
-
- driver._xvfb_process = FakeXvfbProcess()
- driver._lock_file = '/tmp/.X42-lock'
-
- expected_logs = "MOCK kill_process pid: 1234\n"
- OutputCapture().assert_outputs(self, driver.stop, [], expected_logs=expected_logs)
-
- self.assertIsNone(driver._xvfb_process)
- self.assertFalse(port._filesystem.exists(driver._lock_file))