summaryrefslogtreecommitdiffstats
path: root/Tools/Scripts/webkitpy
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-05-16 16:25:10 +0100
committerBen Murdoch <benm@google.com>2011-05-23 18:54:14 +0100
commitab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb (patch)
treedb769fadd053248f85db67434a5b275224defef7 /Tools/Scripts/webkitpy
parent52e2557aeb8477967e97fd24f20f8f407a10fa15 (diff)
downloadexternal_webkit-ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb.zip
external_webkit-ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb.tar.gz
external_webkit-ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb.tar.bz2
Merge WebKit at r76408: Initial merge by git.
Change-Id: I5b91decbd693ccbf5c1b8354b37cd68cc9a1ea53
Diffstat (limited to 'Tools/Scripts/webkitpy')
-rw-r--r--Tools/Scripts/webkitpy/common/config/committers.py3
-rw-r--r--Tools/Scripts/webkitpy/common/host.py80
-rw-r--r--Tools/Scripts/webkitpy/common/system/executive_mock.py10
-rw-r--r--Tools/Scripts/webkitpy/common/system/filesystem.py128
-rw-r--r--Tools/Scripts/webkitpy/common/system/filesystem_mock.py191
-rw-r--r--Tools/Scripts/webkitpy/common/system/workspace.py2
-rw-r--r--Tools/Scripts/webkitpy/common/system/workspace_unittest.py5
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py18
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py10
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py27
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py8
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py14
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py6
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py8
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py23
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py5
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py6
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py6
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py88
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py6
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/__init__.py2
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/base.py13
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py3
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium.py116
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py9
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py1
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py34
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py14
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py52
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py15
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py5
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/config.py4
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/google_chrome.py14
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py64
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/gtk.py8
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/mac.py10
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py33
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/qt.py4
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/test.py303
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/test_files.py42
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py17
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/webkit.py38
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/win.py5
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py186
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py58
-rwxr-xr-xTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py20
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py140
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py5
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py41
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py4
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py4
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py28
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py1
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/queues.py4
-rwxr-xr-xTools/Scripts/webkitpy/tool/main.py51
55 files changed, 1101 insertions, 891 deletions
diff --git a/Tools/Scripts/webkitpy/common/config/committers.py b/Tools/Scripts/webkitpy/common/config/committers.py
index 6a235f5..f7d59fe 100644
--- a/Tools/Scripts/webkitpy/common/config/committers.py
+++ b/Tools/Scripts/webkitpy/common/config/committers.py
@@ -150,7 +150,7 @@ committers_unable_to_review = [
Committer("Krzysztof Kowalczyk", "kkowalczyk@gmail.com"),
Committer("Kwang Yul Seo", ["kwangyul.seo@gmail.com", "skyul@company100.net", "kseo@webkit.org"], "kwangseo"),
Committer("Leandro Pereira", ["leandro@profusion.mobi", "leandro@webkit.org"], "acidx"),
- Committer("Levi Weintraub", "lweintraub@apple.com"),
+ Committer("Levi Weintraub", ["leviw@chromium.org", "leviw@google.com", "lweintraub@apple.com"], "leviw"),
Committer("Lucas De Marchi", ["lucas.demarchi@profusion.mobi", "demarchi@webkit.org"], "demarchi"),
Committer("Luiz Agostini", ["luiz@webkit.org", "luiz.agostini@openbossa.org"], "lca"),
Committer("Mads Ager", "ager@chromium.org"),
@@ -198,6 +198,7 @@ committers_unable_to_review = [
Committer("Yaar Schnitman", ["yaar@chromium.org", "yaar@google.com"]),
Committer("Yong Li", ["yong.li.webkit@gmail.com", "yong.li@torchmobile.com"], "yong"),
Committer("Yongjun Zhang", "yongjun.zhang@nokia.com"),
+ Committer("Yi Shen", ["yi.4.shen@nokia.com", "shenyi2006@gmail.com"]),
Committer("Yuta Kitamura", "yutak@chromium.org", "yutak"),
Committer("Yuzo Fujishima", "yuzo@google.com", "yuzo"),
Committer("Zhenyao Mo", "zmo@google.com", "zhenyao"),
diff --git a/Tools/Scripts/webkitpy/common/host.py b/Tools/Scripts/webkitpy/common/host.py
new file mode 100644
index 0000000..8ec271e
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/host.py
@@ -0,0 +1,80 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Copyright (c) 2009 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 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.common.checkout.api import Checkout
+from webkitpy.common.checkout.scm import default_scm
+from webkitpy.common.config.ports import WebKitPort
+from webkitpy.common.net import bugzilla, buildbot, irc, statusserver
+from webkitpy.common.system import executive, filesystem, platforminfo, user, workspace
+from webkitpy.layout_tests import port
+
+
+class Host(object):
+ def __init__(self):
+ self.bugs = bugzilla.Bugzilla()
+ self.buildbot = buildbot.BuildBot()
+ self.executive = executive.Executive()
+ self._irc = None
+ self.filesystem = filesystem.FileSystem()
+ self.workspace = workspace.Workspace(self.filesystem, self.executive)
+ self._port = None
+ self.user = user.User()
+ self._scm = None
+ self._checkout = None
+ self.status_server = statusserver.StatusServer()
+ self.port_factory = port.factory
+ self.platform = platforminfo.PlatformInfo()
+
+ def _initialize_scm(self, patch_directories=None):
+ self._scm = default_scm(patch_directories)
+ self._checkout = Checkout(self.scm())
+
+ def scm(self):
+ return self._scm
+
+ def checkout(self):
+ return self._checkout
+
+ def port(self):
+ return self._port
+
+ def ensure_irc_connected(self, irc_delegate):
+ if not self._irc:
+ self._irc = irc.ircproxy.IRCProxy(irc_delegate)
+
+ def irc(self):
+ # We don't automatically construct IRCProxy here because constructing
+ # IRCProxy actually connects to IRC. We want clients to explicitly
+ # connect to IRC.
+ return self._irc
+
+ def command_completed(self):
+ if self._irc:
+ self._irc.disconnect()
diff --git a/Tools/Scripts/webkitpy/common/system/executive_mock.py b/Tools/Scripts/webkitpy/common/system/executive_mock.py
index c1cf999..943b70c 100644
--- a/Tools/Scripts/webkitpy/common/system/executive_mock.py
+++ b/Tools/Scripts/webkitpy/common/system/executive_mock.py
@@ -30,6 +30,8 @@
# FIXME: Unify with tool/mocktool.MockExecutive.
+from webkitpy.common.system import executive
+
class MockExecutive2(object):
def __init__(self, output='', exit_code=0, exception=None,
@@ -48,7 +50,7 @@ class MockExecutive2(object):
def kill_process(self, pid):
pass
- def run_command(self, arg_list, return_exit_code=False,
+ def run_command(self, arg_list, error_handler=None, return_exit_code=False,
decode_output=False):
if self._exception:
raise self._exception
@@ -56,4 +58,10 @@ class MockExecutive2(object):
return self._exit_code
if self._run_command_fn:
return self._run_command_fn(arg_list)
+ if self._exit_code and error_handler:
+ script_error = executive.ScriptError(script_args=arg_list,
+ exit_code=self._exit_code,
+ output=self._output)
+ error_handler(script_error)
+
return self._output
diff --git a/Tools/Scripts/webkitpy/common/system/filesystem.py b/Tools/Scripts/webkitpy/common/system/filesystem.py
index 527b6bd..05513a9 100644
--- a/Tools/Scripts/webkitpy/common/system/filesystem.py
+++ b/Tools/Scripts/webkitpy/common/system/filesystem.py
@@ -33,6 +33,7 @@ from __future__ import with_statement
import codecs
import errno
import exceptions
+import glob
import os
import shutil
import tempfile
@@ -43,11 +44,71 @@ class FileSystem(object):
Unless otherwise noted, all paths are allowed to be either absolute
or relative."""
+ def __init__(self):
+ self.sep = os.sep
+
+ def abspath(self, path):
+ return os.path.abspath(path)
+
+ def basename(self, path):
+ """Wraps os.path.basename()."""
+ return os.path.basename(path)
+
+ def copyfile(self, source, destination):
+ """Copies the contents of the file at the given path to the destination
+ path."""
+ shutil.copyfile(source, destination)
+
+ def dirname(self, path):
+ """Wraps os.path.dirname()."""
+ return os.path.dirname(path)
def exists(self, path):
"""Return whether the path exists in the filesystem."""
return os.path.exists(path)
+ def files_under(self, path, dirs_to_skip=[], file_filter=None):
+ """Return the list of all files under the given path in topdown order.
+
+ Args:
+ dirs_to_skip: a list of directories to skip over during the
+ traversal (e.g., .svn, resources, etc.)
+ file_filter: if not None, the filter will be invoked
+ with the filesystem object and the dirname and basename of
+ each file found. The file is included in the result if the
+ callback returns True.
+ """
+ def filter_all(fs, dirpath, basename):
+ return True
+
+ file_filter = file_filter or filter_all
+ files = []
+ if self.isfile(path):
+ if file_filter(self, self.dirname(path), self.basename(path)):
+ files.append(path)
+ return files
+
+ if self.basename(path) in dirs_to_skip:
+ return []
+
+ for (dirpath, dirnames, filenames) in os.walk(path):
+ for d in dirs_to_skip:
+ if d in dirnames:
+ dirnames.remove(d)
+
+ for filename in filenames:
+ if file_filter(self, dirpath, filename):
+ files.append(self.join(dirpath, filename))
+ return files
+
+ def glob(self, path):
+ """Wraps glob.glob()."""
+ return glob.glob(path)
+
+ def isabs(self, path):
+ """Return whether the path is an absolute path."""
+ return os.path.isabs(path)
+
def isfile(self, path):
"""Return whether the path refers to a file."""
return os.path.isfile(path)
@@ -71,14 +132,20 @@ class FileSystem(object):
the directory will self-delete at the end of the block (if the
directory is empty; non-empty directories raise errors). The
directory can be safely deleted inside the block as well, if so
- desired."""
+ desired.
+
+ Note that the object returned is not a string and does not support all of the string
+ methods. If you need a string, coerce the object to a string and go from there.
+ """
class TemporaryDirectory(object):
def __init__(self, **kwargs):
self._kwargs = kwargs
- self._directory_path = None
+ self._directory_path = tempfile.mkdtemp(**self._kwargs)
+
+ def __str__(self):
+ return self._directory_path
def __enter__(self):
- self._directory_path = tempfile.mkdtemp(**self._kwargs)
return self._directory_path
def __exit__(self, type, value, traceback):
@@ -98,6 +165,41 @@ class FileSystem(object):
if e.errno != errno.EEXIST:
raise
+ def move(self, src, dest):
+ shutil.move(src, dest)
+
+ def mtime(self, path):
+ return os.stat(path).st_mtime
+
+ def normpath(self, path):
+ """Wraps os.path.normpath()."""
+ return os.path.normpath(path)
+
+ def open_binary_tempfile(self, suffix):
+ """Create, open, and return a binary temp file. Returns a tuple of the file and the name."""
+ temp_fd, temp_name = tempfile.mkstemp(suffix)
+ f = os.fdopen(temp_fd, 'wb')
+ return f, temp_name
+
+ def open_text_file_for_writing(self, path, append=False):
+ """Returns a file handle suitable for writing to."""
+ mode = 'w'
+ if append:
+ mode = 'a'
+ return codecs.open(path, mode, 'utf8')
+
+ def read_binary_file(self, path):
+ """Return the contents of the file at the given path as a byte string."""
+ with file(path, 'rb') as f:
+ return f.read()
+
+ def read_text_file(self, path):
+ """Return the contents of the file at the given path as a Unicode string.
+
+ The file is read assuming it is a UTF-8 encoded file with no BOM."""
+ with codecs.open(path, 'r', 'utf8') as f:
+ return f.read()
+
class _WindowsError(exceptions.OSError):
"""Fake exception for Linux and Mac."""
pass
@@ -124,8 +226,9 @@ class FileSystem(object):
if retry_timeout_sec < 0:
raise e
- def remove_tree(self, path, ignore_errors=False):
- shutil.rmtree(path, ignore_errors)
+ def rmtree(self, path):
+ """Delete the directory rooted at path, empty or no."""
+ shutil.rmtree(path, ignore_errors=True)
def read_binary_file(self, path):
"""Return the contents of the file at the given path as a byte string."""
@@ -139,6 +242,10 @@ class FileSystem(object):
with codecs.open(path, 'r', 'utf8') as f:
return f.read()
+ def splitext(self, path):
+ """Return (dirname + os.sep + basename, '.' + ext)"""
+ return os.path.splitext(path)
+
def write_binary_file(self, path, contents):
"""Write the contents to the file at the given location."""
with file(path, 'wb') as f:
@@ -150,14 +257,3 @@ class FileSystem(object):
The file is written encoded as UTF-8 with no BOM."""
with codecs.open(path, 'w', 'utf8') as f:
f.write(contents)
-
- def copyfile(self, source, destination):
- """Copies the contents of the file at the given path to the destination
- path."""
- shutil.copyfile(source, destination)
-
- def files_under(self, path):
- """Return the list of all files under the given path."""
- return [self.join(path_to_file, filename)
- for (path_to_file, _, filenames) in os.walk(path)
- for filename in filenames]
diff --git a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py
index 809c4c6..0004944 100644
--- a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py
+++ b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py
@@ -43,10 +43,82 @@ class MockFileSystem(object):
not exist.
"""
self.files = files or {}
+ self.written_files = {}
+ self.sep = '/'
+ self.current_tmpno = 0
+
+ def _raise_not_found(self, path):
+ raise IOError(errno.ENOENT, path, os.strerror(errno.ENOENT))
+
+ def _split(self, path):
+ idx = path.rfind('/')
+ return (path[0:idx], path[idx + 1:])
+
+ def abspath(self, path):
+ return path
+
+ def basename(self, path):
+ return self._split(path)[1]
+
+ def copyfile(self, source, destination):
+ if not self.exists(source):
+ self._raise_not_found(source)
+ if self.isdir(source):
+ raise IOError(errno.EISDIR, source, os.strerror(errno.ISDIR))
+ if self.isdir(destination):
+ raise IOError(errno.EISDIR, destination, os.strerror(errno.ISDIR))
+
+ self.files[destination] = self.files[source]
+
+ def dirname(self, path):
+ return self._split(path)[0]
def exists(self, path):
return self.isfile(path) or self.isdir(path)
+ def files_under(self, path, dirs_to_skip=[], file_filter=None):
+ def filter_all(fs, dirpath, basename):
+ return True
+
+ file_filter = file_filter or filter_all
+ files = []
+ if self.isfile(path):
+ if file_filter(self, self.dirname(path), self.basename(path)):
+ files.append(path)
+ return files
+
+ if self.basename(path) in dirs_to_skip:
+ return []
+
+ if not path.endswith('/'):
+ path += '/'
+
+ dir_substrings = ['/' + d + '/' for d in dirs_to_skip]
+ for filename in self.files:
+ if not filename.startswith(path):
+ continue
+
+ suffix = filename[len(path) - 1:]
+ if any(dir_substring in suffix for dir_substring in dir_substrings):
+ continue
+
+ dirpath, basename = self._split(filename)
+ if file_filter(self, dirpath, basename):
+ files.append(filename)
+
+ return files
+
+ def glob(self, path):
+ # FIXME: This only handles a wildcard '*' at the end of the path.
+ # Maybe it should handle more?
+ if path[-1] == '*':
+ return [f for f in self.files if f.startswith(path[:-1])]
+ else:
+ return [f for f in self.files if f == path]
+
+ def isabs(self, path):
+ return path.startswith('/')
+
def isfile(self, path):
return path in self.files and self.files[path] is not None
@@ -55,7 +127,12 @@ class MockFileSystem(object):
return False
if not path.endswith('/'):
path += '/'
- return any(f.startswith(path) for f in self.files)
+
+ # We need to use a copy of the keys here in order to avoid switching
+ # to a different thread and potentially modifying the dict in
+ # mid-iteration.
+ files = self.files.keys()[:]
+ return any(f.startswith(path) for f in files)
def join(self, *comps):
return re.sub(re.escape(os.path.sep), '/', os.path.join(*comps))
@@ -80,42 +157,114 @@ class MockFileSystem(object):
files.append(remaining)
return dirs + files
+ def mtime(self, path):
+ if self.exists(path):
+ return 0
+ self._raise_not_found(path)
+
+ def _mktemp(self, suffix='', prefix='tmp', dir=None, **kwargs):
+ if dir is None:
+ dir = '/__im_tmp'
+ curno = self.current_tmpno
+ self.current_tmpno += 1
+ return self.join(dir, "%s_%u_%s" % (prefix, curno, suffix))
+
+ def mkdtemp(self, **kwargs):
+ class TemporaryDirectory(object):
+ def __init__(self, fs, **kwargs):
+ self._kwargs = kwargs
+ self._filesystem = fs
+ self._directory_path = fs._mktemp(**kwargs)
+ fs.maybe_make_directory(self._directory_path)
+
+ def __str__(self):
+ return self._directory_path
+
+ def __enter__(self):
+ return self._directory_path
+
+ def __exit__(self, type, value, traceback):
+ # Only self-delete if necessary.
+
+ # FIXME: Should we delete non-empty directories?
+ if self._filesystem.exists(self._directory_path):
+ self._filesystem.rmtree(self._directory_path)
+
+ return TemporaryDirectory(fs=self, **kwargs)
+
def maybe_make_directory(self, *path):
# FIXME: Implement such that subsequent calls to isdir() work?
pass
+ def move(self, src, dst):
+ if self.files[src] is None:
+ self._raise_not_found(src)
+ self.files[dst] = self.files[src]
+ self.files[src] = None
+
+ def normpath(self, path):
+ return path
+
+ def open_binary_tempfile(self, suffix):
+ path = self._mktemp(suffix)
+ return WritableFileObject(self, path), path
+
+ def open_text_file_for_writing(self, path, append=False):
+ return WritableFileObject(self, path, append)
+
def read_text_file(self, path):
return self.read_binary_file(path)
def read_binary_file(self, path):
- if path in self.files:
- if self.files[path] is None:
- raise IOError(errno.ENOENT, path, os.strerror(errno.ENOENT))
- return self.files[path]
+ # Intentionally raises KeyError if we don't recognize the path.
+ if self.files[path] is None:
+ self._raise_not_found(path)
+ return self.files[path]
+
+ def remove(self, path):
+ if self.files[path] is None:
+ self._raise_not_found(path)
+ self.files[path] = None
+
+ def rmtree(self, path):
+ if not path.endswith('/'):
+ path += '/'
+
+ for f in self.files:
+ if f.startswith(path):
+ self.files[f] = None
+
+ def splitext(self, path):
+ idx = path.rfind('.')
+ if idx == -1:
+ idx = 0
+ return (path[0:idx], path[idx:])
def write_text_file(self, path, contents):
return self.write_binary_file(path, contents)
def write_binary_file(self, path, contents):
self.files[path] = contents
+ self.written_files[path] = contents
- def copyfile(self, source, destination):
- if not self.exists(source):
- raise IOError(errno.ENOENT, source, os.strerror(errno.ENOENT))
- if self.isdir(source):
- raise IOError(errno.EISDIR, source, os.strerror(errno.ISDIR))
- if self.isdir(destination):
- raise IOError(errno.EISDIR, destination, os.strerror(errno.ISDIR))
- self.files[destination] = self.files[source]
+class WritableFileObject(object):
+ def __init__(self, fs, path, append=False, encoding=None):
+ self.fs = fs
+ self.path = path
+ self.closed = False
+ if path not in self.fs.files or not append:
+ self.fs.files[path] = ""
- def files_under(self, path):
- if not path.endswith('/'):
- path += '/'
- return [file for file in self.files if file.startswith(path)]
+ def __enter__(self):
+ return self
- def remove(self, path):
- del self.files[path]
+ def __exit__(self, type, value, traceback):
+ self.close()
+
+ def close(self):
+ self.closed = True
- def remove_tree(self, path, ignore_errors=False):
- self.files = [file for file in self.files if not file.startswith(path)]
+ def write(self, str):
+ self.fs.files[self.path] += str
+ self.fs.written_files[self.path] = self.fs.files[self.path]
diff --git a/Tools/Scripts/webkitpy/common/system/workspace.py b/Tools/Scripts/webkitpy/common/system/workspace.py
index 3b755ad..afb0009 100644
--- a/Tools/Scripts/webkitpy/common/system/workspace.py
+++ b/Tools/Scripts/webkitpy/common/system/workspace.py
@@ -36,7 +36,7 @@ class Workspace(object):
self._filesystem = filesystem
self._executive = executive # FIXME: Remove if create_zip is moved to python.
- def find_unused_filename(self, directory, name, extension, search_limit=10):
+ def find_unused_filename(self, directory, name, extension, search_limit=100):
for count in range(search_limit):
if count:
target_name = "%s-%s.%s" % (name, count, extension)
diff --git a/Tools/Scripts/webkitpy/common/system/workspace_unittest.py b/Tools/Scripts/webkitpy/common/system/workspace_unittest.py
index e5fbb26..6be7664 100644
--- a/Tools/Scripts/webkitpy/common/system/workspace_unittest.py
+++ b/Tools/Scripts/webkitpy/common/system/workspace_unittest.py
@@ -40,10 +40,13 @@ class WorkspaceTest(unittest.TestCase):
filesystem = MockFileSystem({
"dir/foo.jpg": "",
"dir/foo-1.jpg": "",
+ "dir/foo-2.jpg": "",
})
workspace = Workspace(filesystem, None)
self.assertEqual(workspace.find_unused_filename("bar", "bar", "bar"), "bar/bar.bar")
- self.assertEqual(workspace.find_unused_filename("dir", "foo", "jpg"), "dir/foo-2.jpg")
+ self.assertEqual(workspace.find_unused_filename("dir", "foo", "jpg", search_limit=1), None)
+ self.assertEqual(workspace.find_unused_filename("dir", "foo", "jpg", search_limit=2), None)
+ self.assertEqual(workspace.find_unused_filename("dir", "foo", "jpg"), "dir/foo-3.jpg")
def test_create_zip(self):
workspace = Workspace(None, MockExecutive(should_log=True))
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py
index 2bb2d02..050eefa 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py
@@ -36,9 +36,6 @@ the output. When there are no more URLs to process in the shared queue, the
thread exits.
"""
-from __future__ import with_statement
-
-import codecs
import copy
import logging
import os
@@ -86,6 +83,7 @@ def _process_output(port, options, test_input, test_types, test_args,
Returns: a TestResult object
"""
failures = []
+ fs = port._filesystem
if test_output.crash:
failures.append(test_failures.FailureCrash())
@@ -96,11 +94,10 @@ def _process_output(port, options, test_input, test_types, test_args,
if test_output.crash:
_log.debug("%s Stacktrace for %s:\n%s" % (worker_name, test_name,
test_output.error))
- filename = os.path.join(options.results_directory, test_name)
- filename = os.path.splitext(filename)[0] + "-stack.txt"
- port.maybe_make_directory(os.path.split(filename)[0])
- with codecs.open(filename, "wb", "utf-8") as file:
- file.write(test_output.error)
+ filename = fs.join(options.results_directory, test_name)
+ filename = fs.splitext(filename)[0] + "-stack.txt"
+ fs.maybe_make_directory(fs.dirname(filename))
+ fs.write_text_file(filename, test_output.error)
elif test_output.error:
_log.debug("%s %s output stderr lines:\n%s" % (worker_name, test_name,
test_output.error))
@@ -385,10 +382,9 @@ class TestShellThread(WatchableThread):
# Append tests we're running to the existing tests_run.txt file.
# This is created in run_webkit_tests.py:_PrepareListsAndPrintOutput.
- tests_run_filename = os.path.join(self._options.results_directory,
+ tests_run_filename = self._port._filesystem.join(self._options.results_directory,
"tests_run.txt")
- tests_run_file = codecs.open(tests_run_filename, "a", "utf-8")
-
+ tests_run_file = self._port._filesystem.open_text_file_for_writing(tests_run_filename, append=False)
while True:
if self._canceled:
_log.debug('Testing cancelled')
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py
index b054c5b..3267fb7 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py
@@ -27,7 +27,6 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import logging
-import os
from webkitpy.layout_tests.layout_package import json_results_generator
from webkitpy.layout_tests.layout_package import test_expectations
@@ -66,12 +65,11 @@ class JSONLayoutResultsGenerator(json_results_generator.JSONResultsGeneratorBase
results.
"""
super(JSONLayoutResultsGenerator, self).__init__(
- builder_name, build_name, build_number, results_file_base_path,
+ port, builder_name, build_name, build_number, results_file_base_path,
builder_base_url, {}, port.test_repository_paths(),
generate_incremental_results, test_results_server,
test_type, master_name)
- self._port = port
self._expectations = expectations
# We want relative paths to LayoutTest root for JSON output.
@@ -181,9 +179,9 @@ class JSONLayoutResultsGenerator(json_results_generator.JSONResultsGeneratorBase
test, test_name, tests)
# Remove tests that don't exist anymore.
- full_path = os.path.join(self._port.layout_tests_dir(), test_name)
- full_path = os.path.normpath(full_path)
- if not os.path.exists(full_path):
+ full_path = self._fs.join(self._port.layout_tests_dir(), test_name)
+ full_path = self._fs.normpath(full_path)
+ if not self._fs.exists(full_path):
del tests[test_name]
def _get_failure_summary_entry(self, timeline):
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py
index 12e65b2..32ffd71 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py
@@ -26,11 +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.
-from __future__ import with_statement
-
-import codecs
import logging
-import os
import subprocess
import sys
import time
@@ -118,7 +114,7 @@ class JSONResultsGeneratorBase(object):
URL_FOR_TEST_LIST_JSON = \
"http://%s/testfile?builder=%s&name=%s&testlistjson=1&testtype=%s"
- def __init__(self, builder_name, build_name, build_number,
+ def __init__(self, port, builder_name, build_name, build_number,
results_file_base_path, builder_base_url,
test_results_map, svn_repositories=None,
generate_incremental_results=False,
@@ -129,6 +125,7 @@ class JSONResultsGeneratorBase(object):
if it is not found locally.
Args
+ port: port-specific wrapper
builder_name: the builder name (e.g. Webkit).
build_name: the build name (e.g. webkit-rel).
build_number: the build number.
@@ -146,14 +143,16 @@ class JSONResultsGeneratorBase(object):
test_type: test type string (e.g. 'layout-tests').
master_name: the name of the buildbot master.
"""
+ self._port = port
+ self._fs = port._filesystem
self._builder_name = builder_name
self._build_name = build_name
self._build_number = build_number
self._builder_base_url = builder_base_url
self._results_directory = results_file_base_path
- self._results_file_path = os.path.join(results_file_base_path,
+ self._results_file_path = self._fs.join(results_file_base_path,
self.RESULTS_FILENAME)
- self._incremental_results_file_path = os.path.join(
+ self._incremental_results_file_path = self._fs.join(
results_file_base_path, self.INCREMENTAL_RESULTS_FILENAME)
self._test_results_map = test_results_map
@@ -254,7 +253,7 @@ class JSONResultsGeneratorBase(object):
("testtype", self._test_type),
("master", self._master_name)]
- files = [(file, os.path.join(self._results_directory, file))
+ files = [(file, self._fs.join(self._results_directory, file))
for file in json_files]
uploader = test_results_uploader.TestResultsUploader(
@@ -273,10 +272,7 @@ class JSONResultsGeneratorBase(object):
# Specify separators in order to get compact encoding.
json_data = simplejson.dumps(json, separators=(',', ':'))
json_string = self.JSON_PREFIX + json_data + self.JSON_SUFFIX
-
- results_file = codecs.open(file_path, "w", "utf-8")
- results_file.write(json_string)
- results_file.close()
+ self._fs.write_text_file(file_path, json_string)
def _get_test_timing(self, test_name):
"""Returns test timing data (elapsed time) in second
@@ -330,7 +326,7 @@ class JSONResultsGeneratorBase(object):
Args:
in_directory: The directory where svn is to be run.
"""
- if os.path.exists(os.path.join(in_directory, '.svn')):
+ if self._fs.exists(self._fs.join(in_directory, '.svn')):
# Note: Not thread safe: http://bugs.python.org/issue2320
output = subprocess.Popen(["svn", "info", "--xml"],
cwd=in_directory,
@@ -358,9 +354,8 @@ class JSONResultsGeneratorBase(object):
old_results = None
error = None
- if os.path.exists(self._results_file_path) and not for_incremental:
- with codecs.open(self._results_file_path, "r", "utf-8") as file:
- old_results = file.read()
+ if self._fs.exists(self._results_file_path) and not for_incremental:
+ old_results = self._fs.read_text_file(self._results_file_path)
elif self._builder_base_url or for_incremental:
if for_incremental:
if not self._test_results_server:
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py
index dad549a..ce99765 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py
@@ -31,11 +31,11 @@
import unittest
import optparse
import random
-import shutil
-import tempfile
+from webkitpy.common.system import filesystem_mock
from webkitpy.layout_tests.layout_package import json_results_generator
from webkitpy.layout_tests.layout_package import test_expectations
+from webkitpy.thirdparty.mock import Mock
class JSONGeneratorTest(unittest.TestCase):
@@ -83,7 +83,9 @@ class JSONGeneratorTest(unittest.TestCase):
failed=(test in failed_tests),
elapsed_time=test_timings[test])
- generator = json_results_generator.JSONResultsGeneratorBase(
+ port = Mock()
+ port._filesystem = filesystem_mock.MockFileSystem()
+ generator = json_results_generator.JSONResultsGeneratorBase(port,
self.builder_name, self.build_name, self.build_number,
'',
None, # don't fetch past json results archive
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py
index e0ca8db..481c617 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py
@@ -144,6 +144,13 @@ class MultiThreadedBroker(WorkerMessageBroker):
some_thread_is_alive = False
t = time.time()
for thread in threads:
+ if thread.isAlive():
+ some_thread_is_alive = True
+ next_timeout = thread.next_timeout()
+ if next_timeout and t > next_timeout:
+ log_wedged_worker(thread.getName(), thread.id())
+ thread.clear_next_timeout()
+
exception_info = thread.exception_info()
if exception_info is not None:
# Re-raise the thread's exception here to make it
@@ -152,13 +159,6 @@ class MultiThreadedBroker(WorkerMessageBroker):
# to have passed.
raise exception_info[0], exception_info[1], exception_info[2]
- if thread.isAlive():
- some_thread_is_alive = True
- next_timeout = thread.next_timeout()
- if next_timeout and t > next_timeout:
- log_wedged_worker(thread.getName(), thread.id())
- thread.clear_next_timeout()
-
self._test_runner.update()
if some_thread_is_alive:
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py
index 7a6aad1..e10ad99 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py
@@ -31,8 +31,6 @@
import logging
import optparse
-import os
-import pdb
from webkitpy.layout_tests.layout_package import metered_stream
from webkitpy.layout_tests.layout_package import test_expectations
@@ -411,7 +409,7 @@ class Printer(object):
return
next_test = test_list[self._current_test_number]
- next_dir = os.path.dirname(
+ next_dir = self._port._filesystem.dirname(
self._port.relative_test_filename(next_test))
if self._current_progress_str == "":
self._current_progress_str = "%s: " % (next_dir)
@@ -437,7 +435,7 @@ class Printer(object):
break
next_test = test_list[self._current_test_number]
- next_dir = os.path.dirname(
+ next_dir = self._port._filesystem.dirname(
self._port.relative_test_filename(next_test))
if result_summary.remaining:
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py
index 9280b02..12a786e 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py
@@ -29,10 +29,7 @@
"""Unit tests for printing.py."""
-import os
import optparse
-import pdb
-import sys
import unittest
import logging
@@ -117,6 +114,7 @@ class TestUtilityFunctions(unittest.TestCase):
class Testprinter(unittest.TestCase):
def get_printer(self, args=None, single_threaded=False,
is_fully_parallel=False):
+ args = args or []
printing_options = printing.print_options()
option_parser = optparse.OptionParser(option_list=printing_options)
options, args = option_parser.parse_args(args)
@@ -138,11 +136,11 @@ class Testprinter(unittest.TestCase):
failures = [test_failures.FailureTimeout()]
elif result_type == test_expectations.CRASH:
failures = [test_failures.FailureCrash()]
- path = os.path.join(self._port.layout_tests_dir(), test)
+ path = self._port._filesystem.join(self._port.layout_tests_dir(), test)
return test_results.TestResult(path, failures=failures, test_run_time=run_time)
def get_result_summary(self, tests, expectations_str):
- test_paths = [os.path.join(self._port.layout_tests_dir(), test) for
+ test_paths = [self._port._filesystem.join(self._port.layout_tests_dir(), test) for
test in tests]
expectations = test_expectations.TestExpectations(
self._port, test_paths, expectations_str,
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py
index 8645fc1..806b663 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py
@@ -32,9 +32,7 @@ for layout tests.
"""
import logging
-import os
import re
-import sys
import webkitpy.thirdparty.simplejson as simplejson
@@ -322,6 +320,7 @@ class TestExpectationsFile:
"""
self._port = port
+ self._fs = port._filesystem
self._expectations = expectations
self._full_test_list = full_test_list
self._test_platform_name = test_platform_name
@@ -690,9 +689,9 @@ class TestExpectationsFile:
'indefinitely, then it should be just timeout.',
test_list_path)
- full_path = os.path.join(self._port.layout_tests_dir(),
- test_list_path)
- full_path = os.path.normpath(full_path)
+ full_path = self._fs.join(self._port.layout_tests_dir(),
+ test_list_path)
+ full_path = self._fs.normpath(full_path)
# WebKit's way of skipping tests is to add a -disabled suffix.
# So we should consider the path existing if the path or the
# -disabled version exists.
@@ -736,11 +735,11 @@ class TestExpectationsFile:
# lists to represent the tree of tests, leaves being test
# files and nodes being categories.
- path = os.path.join(self._port.layout_tests_dir(), test_list_path)
- path = os.path.normpath(path)
- if self._port.path_isdir(path):
+ path = self._fs.join(self._port.layout_tests_dir(), test_list_path)
+ path = self._fs.normpath(path)
+ if self._fs.isdir(path):
# this is a test category, return all the tests of the category.
- path = os.path.join(path, '')
+ path = self._fs.join(path, '')
return [test for test in self._full_test_list if test.startswith(path)]
@@ -817,7 +816,7 @@ class TestExpectationsFile:
self._remove_from_sets(test, self._timeline_to_tests)
self._remove_from_sets(test, self._result_type_to_tests)
- self._test_list_paths[test] = os.path.normpath(test_list_path)
+ self._test_list_paths[test] = self._fs.normpath(test_list_path)
def _remove_from_sets(self, test, dict):
"""Removes the given test from the sets in the dictionary.
@@ -838,7 +837,7 @@ class TestExpectationsFile:
return False
prev_base_path = self._test_list_paths[test]
- if (prev_base_path == os.path.normpath(test_list_path)):
+ if (prev_base_path == self._fs.normpath(test_list_path)):
if (not allow_overrides or test in self._overridding_tests):
if allow_overrides:
expectation_source = "override"
@@ -854,7 +853,7 @@ class TestExpectationsFile:
return False
# Check if we've already seen a more precise path.
- return prev_base_path.startswith(os.path.normpath(test_list_path))
+ return prev_base_path.startswith(self._fs.normpath(test_list_path))
def _add_error(self, lineno, msg, path):
"""Reports an error that will prevent running the tests. Does not
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py
index 34771f3..8f9e5dd 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py
@@ -29,8 +29,6 @@
"""Unit tests for test_expectations.py."""
-import os
-import sys
import unittest
from webkitpy.layout_tests import port
@@ -82,11 +80,12 @@ class FunctionsTest(unittest.TestCase):
class Base(unittest.TestCase):
def __init__(self, testFunc, setUp=None, tearDown=None, description=None):
self._port = port.get('test', None)
+ self._fs = self._port._filesystem
self._exp = None
unittest.TestCase.__init__(self, testFunc)
def get_test(self, test_name):
- return os.path.join(self._port.layout_tests_dir(), test_name)
+ return self._fs.join(self._port.layout_tests_dir(), test_name)
def get_basic_tests(self):
return [self.get_test('failures/expected/text.html'),
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py
index 2b8190b..eb59d36 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py
@@ -29,7 +29,6 @@
"""Classes for failures that occur during tests."""
-import os
import test_expectations
import cPickle
@@ -121,7 +120,10 @@ class TestFailure(object):
Return:
The relative windows path to the output filename
"""
- return os.path.splitext(filename)[0] + modifier
+ # FIXME: technically this breaks if files don't use ".ext" to indicate
+ # the extension, but passing in a Filesystem object here is a huge
+ # hassle.
+ return filename[:filename.rfind('.')] + modifier
class FailureWithType(TestFailure):
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py
index b2698d1..c5aa2d6 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py
@@ -89,6 +89,12 @@ class Test(unittest.TestCase):
crash_set = set([FailureCrash(), "FailureCrash"])
self.assertEqual(len(crash_set), 2)
+ def test_relative_output_filename(self):
+ # This could be any Failure* object, since we're testing a method
+ # on the base class.
+ failure_obj = FailureTextMismatch()
+ actual_filename = failure_obj.relative_output_filename("fast/html/article-element.html", "-actual.txt")
+ self.assertEquals(actual_filename, "fast/html/article-element-actual.txt")
if __name__ == '__main__':
unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py
index 5b02a00..6c07850 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py
@@ -37,14 +37,11 @@ create a final report.
from __future__ import with_statement
-import codecs
import errno
import logging
import math
-import os
import Queue
import random
-import shutil
import sys
import time
@@ -68,8 +65,6 @@ _log = logging.getLogger("webkitpy.layout_tests.run_webkit_tests")
# Builder base URL where we have the archived test results.
BUILDER_BASE_URL = "http://build.chromium.org/buildbot/layout_test_results/"
-LAYOUT_TESTS_DIRECTORY = "LayoutTests" + os.sep
-
TestExpectationsFile = test_expectations.TestExpectationsFile
@@ -160,8 +155,6 @@ class TestRunner:
"""A class for managing running a series of tests on a series of layout
test files."""
- HTTP_SUBDIR = os.sep.join(['', 'http', ''])
- WEBSOCKET_SUBDIR = os.sep.join(['', 'websocket', ''])
# The per-test timeout in milliseconds, if no --time-out-ms option was
# given to run_webkit_tests. This should correspond to the default timeout
@@ -177,10 +170,16 @@ class TestRunner:
printer: a Printer object to record updates to.
"""
self._port = port
+ self._fs = port._filesystem
self._options = options
self._printer = printer
self._message_broker = None
+ self.HTTP_SUBDIR = self._fs.join('', 'http', '')
+ self.WEBSOCKET_SUBDIR = self._fs.join('', 'websocket', '')
+ self.LAYOUT_TESTS_DIRECTORY = "LayoutTests" + self._fs.sep
+
+
# disable wss server. need to install pyOpenSSL on buildbots.
# self._websocket_secure_server = websocket_server.PyWebSocket(
# options.results_directory, use_tls=True, port=9323)
@@ -199,15 +198,18 @@ class TestRunner:
last_unexpected_results: list of unexpected results to retest, if any
"""
- paths = [self._strip_test_dir_prefix(arg) for arg in args if arg and arg != '']
+ paths = self._strip_test_dir_prefixes(args)
paths += last_unexpected_results
if self._options.test_list:
- paths += read_test_files(self._options.test_list)
+ paths += self._strip_test_dir_prefixes(read_test_files(self._fs, self._options.test_list))
self._test_files = self._port.tests(paths)
+ def _strip_test_dir_prefixes(self, paths):
+ return [self._strip_test_dir_prefix(path) for path in paths if path]
+
def _strip_test_dir_prefix(self, path):
- if path.startswith(LAYOUT_TESTS_DIRECTORY):
- return path[len(LAYOUT_TESTS_DIRECTORY):]
+ if path.startswith(self.LAYOUT_TESTS_DIRECTORY):
+ return path[len(self.LAYOUT_TESTS_DIRECTORY):]
return path
def lint(self):
@@ -339,10 +341,9 @@ class TestRunner:
self._printer.print_expected(extra_msg)
tests_run_msg += "\n" + extra_msg
files.extend(test_files[0:extra])
- tests_run_filename = os.path.join(self._options.results_directory,
+ tests_run_filename = self._fs.join(self._options.results_directory,
"tests_run.txt")
- with codecs.open(tests_run_filename, "w", "utf-8") as file:
- file.write(tests_run_msg + "\n")
+ self._fs.write_text_file(tests_run_filename, tests_run_msg)
len_skip_chunk = int(len(files) * len(skipped) /
float(len(self._test_files)))
@@ -390,15 +391,20 @@ class TestRunner:
result_summary.add(result, expected=True)
self._printer.print_expected('')
+ # Check to make sure we didn't filter out all of the tests.
+ if not len(self._test_files):
+ _log.info("All tests are being skipped")
+ return None
+
return result_summary
def _get_dir_for_test_file(self, test_file):
"""Returns the highest-level directory by which to shard the given
test file."""
- index = test_file.rfind(os.sep + LAYOUT_TESTS_DIRECTORY)
+ index = test_file.rfind(self._fs.sep + self.LAYOUT_TESTS_DIRECTORY)
- test_file = test_file[index + len(LAYOUT_TESTS_DIRECTORY):]
- test_file_parts = test_file.split(os.sep, 1)
+ test_file = test_file[index + len(self.LAYOUT_TESTS_DIRECTORY):]
+ test_file_parts = test_file.split(self._fs.sep, 1)
directory = test_file_parts[0]
test_file = test_file_parts[1]
@@ -408,10 +414,10 @@ class TestRunner:
# what made them stable on linux/mac.
return_value = directory
while ((directory != 'http' or sys.platform in ('darwin', 'linux2'))
- and test_file.find(os.sep) >= 0):
- test_file_parts = test_file.split(os.sep, 1)
+ and test_file.find(self._fs.sep) >= 0):
+ test_file_parts = test_file.split(self._fs.sep, 1)
directory = test_file_parts[0]
- return_value = os.path.join(return_value, directory)
+ return_value = self._fs.join(return_value, directory)
test_file = test_file_parts[1]
return return_value
@@ -427,7 +433,7 @@ class TestRunner:
def _test_requires_lock(self, test_file):
"""Return True if the test needs to be locked when
running multiple copies of NRWTs."""
- split_path = test_file.split(os.sep)
+ split_path = test_file.split(self._port._filesystem.sep)
return 'http' in split_path or 'websocket' in split_path
def _test_is_slow(self, test_file):
@@ -757,10 +763,9 @@ class TestRunner:
layout_tests_dir = self._port.layout_tests_dir()
possible_dirs = self._port.test_dirs()
for dirname in possible_dirs:
- if os.path.isdir(os.path.join(layout_tests_dir, dirname)):
- shutil.rmtree(os.path.join(self._options.results_directory,
- dirname),
- ignore_errors=True)
+ if self._fs.isdir(self._fs.join(layout_tests_dir, dirname)):
+ self._fs.rmtree(self._fs.join(self._options.results_directory,
+ dirname))
def _get_failures(self, result_summary, include_crashes):
"""Filters a dict of results and returns only the failures.
@@ -803,17 +808,17 @@ class TestRunner:
"""
results_directory = self._options.results_directory
_log.debug("Writing JSON files in %s." % results_directory)
- unexpected_json_path = os.path.join(results_directory, "unexpected_results.json")
- with codecs.open(unexpected_json_path, "w", "utf-8") as file:
+ unexpected_json_path = self._fs.join(results_directory, "unexpected_results.json")
+ with self._fs.open_text_file_for_writing(unexpected_json_path) as file:
simplejson.dump(unexpected_results, file, sort_keys=True, indent=2)
# Write a json file of the test_expectations.txt file for the layout
# tests dashboard.
- expectations_path = os.path.join(results_directory, "expectations.json")
+ expectations_path = self._fs.join(results_directory, "expectations.json")
expectations_json = \
self._expectations.get_expectations_json_for_all_platforms()
- with codecs.open(expectations_path, "w", "utf-8") as file:
- file.write(u"ADD_EXPECTATIONS(%s);" % expectations_json)
+ self._fs.write_text_file(expectations_path,
+ u"ADD_EXPECTATIONS(%s);" % expectations_json)
generator = json_layout_results_generator.JSONLayoutResultsGenerator(
self._port, self._options.builder_name, self._options.build_name,
@@ -1184,9 +1189,9 @@ class TestRunner:
if not len(test_files):
return False
- out_filename = os.path.join(self._options.results_directory,
- "results.html")
- with codecs.open(out_filename, "w", "utf-8") as results_file:
+ out_filename = self._fs.join(self._options.results_directory,
+ "results.html")
+ with self._fs.open_text_file_for_writing(out_filename) as results_file:
html = self._results_html(test_files, result_summary.failures, results_title)
results_file.write(html)
@@ -1194,21 +1199,20 @@ class TestRunner:
def _show_results_html_file(self):
"""Shows the results.html page."""
- results_filename = os.path.join(self._options.results_directory,
- "results.html")
+ results_filename = self._fs.join(self._options.results_directory,
+ "results.html")
self._port.show_results_html_file(results_filename)
-def read_test_files(files):
+def read_test_files(fs, files):
tests = []
for file in files:
try:
- with codecs.open(file, 'r', 'utf-8') as file_contents:
- # FIXME: This could be cleaner using a list comprehension.
- for line in file_contents:
- line = test_expectations.strip_comments(line)
- if line:
- tests.append(line)
+ file_contents = fs.read_text_file(file).split('\n')
+ for line in file_contents:
+ line = test_expectations.strip_comments(line)
+ if line:
+ tests.append(line)
except IOError, e:
if e.errno == errno.ENOENT:
_log.critical('')
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py
index 3c564ae..97f8630 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py
@@ -32,6 +32,7 @@
import unittest
+from webkitpy.common.system import filesystem_mock
from webkitpy.thirdparty.mock import Mock
import test_runner
@@ -45,6 +46,7 @@ class TestRunnerWrapper(test_runner.TestRunner):
class TestRunnerTest(unittest.TestCase):
def test_results_html(self):
mock_port = Mock()
+ mock_port._filesystem = filesystem_mock.MockFileSystem()
mock_port.relative_test_filename = lambda name: name
mock_port.filename_to_uri = lambda name: name
@@ -66,7 +68,9 @@ class TestRunnerTest(unittest.TestCase):
def test_shard_tests(self):
# Test that _shard_tests in test_runner.TestRunner really
# put the http tests first in the queue.
- runner = TestRunnerWrapper(port=Mock(), options=Mock(),
+ port = Mock()
+ port._filesystem = filesystem_mock.MockFileSystem()
+ runner = TestRunnerWrapper(port=port, options=Mock(),
printer=Mock())
test_list = [
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/__init__.py b/Tools/Scripts/webkitpy/layout_tests/port/__init__.py
index e3ad6f4..59ab2ef 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/__init__.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/__init__.py
@@ -30,3 +30,5 @@
"""Port-specific entrypoints for the layout tests test infrastructure."""
from factory import get
+
+from test import unit_test_filesystem
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base.py b/Tools/Scripts/webkitpy/layout_tests/port/base.py
index 97b54c9..6e5fabc 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -117,7 +117,10 @@ class Port(object):
self._pretty_patch_path = self.path_from_webkit_base("Websites",
"bugs.webkit.org", "PrettyPatch", "prettify.rb")
- self._pretty_patch_available = True
+ # If we're running on a mocked-out filesystem, this file almost
+ # certainly won't be available, so it's a good test to keep us
+ # from erroring out later.
+ self._pretty_patch_available = self._filesystem.exists(self._pretty_patch_path)
self.set_option_default('configuration', None)
if self._options.configuration is None:
self._options.configuration = self.default_configuration()
@@ -244,7 +247,7 @@ class Port(object):
tree)
results_filename - relative path from top of tree to the results
file
- (os.path.join of the two gives you the full path to the file,
+ (port.join() of the two gives you the full path to the file,
unless None was returned.)
Return values will be in the format appropriate for the current
platform (e.g., "\\" for path separators on Windows). If the results
@@ -255,7 +258,7 @@ class Port(object):
conjunction with the other baseline and filename routines that are
platform specific.
"""
- testname = os.path.splitext(self.relative_test_filename(filename))[0]
+ testname = self._filesystem.splitext(self.relative_test_filename(filename))[0]
baseline_filename = testname + '-expected' + suffix
@@ -360,7 +363,7 @@ class Port(object):
protocol = "http"
return "%s://127.0.0.1:%u/%s" % (protocol, port, relative_path)
- return path.abspath_to_uri(os.path.abspath(filename))
+ return path.abspath_to_uri(self._filesystem.abspath(filename))
def tests(self, paths):
"""Return the list of tests found (relative to layout_tests_dir()."""
@@ -702,7 +705,7 @@ class Port(object):
def pretty_patch_text(self, diff_path):
if not self._pretty_patch_available:
return self._pretty_patch_error_html
- command = ("ruby", "-I", os.path.dirname(self._pretty_patch_path),
+ command = ("ruby", "-I", self._filesystem.dirname(self._pretty_patch_path),
self._pretty_patch_path, diff_path)
try:
# Diffs are treated as binary (we pass decode_output=False) as they
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
index 8d586e3..72f2d05 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
@@ -27,7 +27,6 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import optparse
-import os
import sys
import tempfile
import unittest
@@ -194,7 +193,7 @@ class PortTest(unittest.TestCase):
def test_filename_to_uri(self):
port = base.Port()
layout_test_dir = port.layout_tests_dir()
- test_file = os.path.join(layout_test_dir, "foo", "bar.html")
+ test_file = port._filesystem.join(layout_test_dir, "foo", "bar.html")
# On Windows, absolute paths are of the form "c:\foo.txt". However,
# all current browsers (except for Opera) normalize file URLs by
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
index 7e934a8..ad1bea6 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
@@ -29,21 +29,16 @@
"""Chromium implementations of the Port interface."""
-from __future__ import with_statement
-
-import codecs
import errno
import logging
-import os
import re
-import shutil
import signal
import subprocess
import sys
-import tempfile
import time
import webbrowser
+from webkitpy.common.system import executive
from webkitpy.common.system.path import cygpath
from webkitpy.layout_tests.layout_package import test_expectations
from webkitpy.layout_tests.layout_package import test_output
@@ -61,26 +56,6 @@ _log = logging.getLogger("webkitpy.layout_tests.port.chromium")
# FIXME: This function doesn't belong in this package.
-def check_file_exists(path_to_file, file_description, override_step=None,
- logging=True):
- """Verify the file is present where expected or log an error.
-
- Args:
- file_name: The (human friendly) name or description of the file
- you're looking for (e.g., "HTTP Server"). Used for error logging.
- override_step: An optional string to be logged if the check fails.
- logging: Whether or not log the error messages."""
- if not os.path.exists(path_to_file):
- if logging:
- _log.error('Unable to find %s' % file_description)
- _log.error(' at %s' % path_to_file)
- if override_step:
- _log.error(' %s' % override_step)
- _log.error('')
- return False
- return True
-
-
class ChromiumPort(base.Port):
"""Abstract base class for Chromium implementations of the Port class."""
@@ -88,6 +63,26 @@ class ChromiumPort(base.Port):
base.Port.__init__(self, **kwargs)
self._chromium_base_dir = None
+ def _check_file_exists(self, path_to_file, file_description,
+ override_step=None, logging=True):
+ """Verify the file is present where expected or log an error.
+
+ Args:
+ file_name: The (human friendly) name or description of the file
+ you're looking for (e.g., "HTTP Server"). Used for error logging.
+ override_step: An optional string to be logged if the check fails.
+ logging: Whether or not log the error messages."""
+ if not self._filesystem.exists(path_to_file):
+ if logging:
+ _log.error('Unable to find %s' % file_description)
+ _log.error(' at %s' % path_to_file)
+ if override_step:
+ _log.error(' %s' % override_step)
+ _log.error('')
+ return False
+ return True
+
+
def baseline_path(self):
return self._webkit_baseline_path(self._name)
@@ -95,8 +90,8 @@ class ChromiumPort(base.Port):
result = True
dump_render_tree_binary_path = self._path_to_driver()
- result = check_file_exists(dump_render_tree_binary_path,
- 'test driver') and result
+ result = self._check_file_exists(dump_render_tree_binary_path,
+ 'test driver') and result
if result and self.get_option('build'):
result = self._check_driver_build_up_to_date(
self.get_option('configuration'))
@@ -105,8 +100,8 @@ class ChromiumPort(base.Port):
helper_path = self._path_to_helper()
if helper_path:
- result = check_file_exists(helper_path,
- 'layout test helper') and result
+ result = self._check_file_exists(helper_path,
+ 'layout test helper') and result
if self.get_option('pixel_tests'):
result = self.check_image_diff(
@@ -120,29 +115,35 @@ class ChromiumPort(base.Port):
def check_sys_deps(self, needs_http):
cmd = [self._path_to_driver(), '--check-layout-test-sys-deps']
- if self._executive.run_command(cmd, return_exit_code=True):
+
+ local_error = executive.ScriptError()
+
+ def error_handler(script_error):
+ local_error.exit_code = script_error.exit_code
+
+ output = self._executive.run_command(cmd, error_handler=error_handler)
+ if local_error.exit_code:
_log.error('System dependencies check failed.')
_log.error('To override, invoke with --nocheck-sys-deps')
_log.error('')
+ _log.error(output)
return False
return True
def check_image_diff(self, override_step=None, logging=True):
image_diff_path = self._path_to_image_diff()
- return check_file_exists(image_diff_path, 'image diff exe',
- override_step, logging)
+ return self._check_file_exists(image_diff_path, 'image diff exe',
+ override_step, logging)
def diff_image(self, expected_contents, actual_contents,
diff_filename=None):
executable = self._path_to_image_diff()
- tempdir = tempfile.mkdtemp()
- expected_filename = os.path.join(tempdir, "expected.png")
- with open(expected_filename, 'w+b') as file:
- file.write(expected_contents)
- actual_filename = os.path.join(tempdir, "actual.png")
- with open(actual_filename, 'w+b') as file:
- file.write(actual_contents)
+ tempdir = self._filesystem.mkdtemp()
+ expected_filename = self._filesystem.join(str(tempdir), "expected.png")
+ self._filesystem.write_binary_file(expected_filename, expected_contents)
+ actual_filename = self._filesystem.join(str(tempdir), "actual.png")
+ self._filesystem.write_binary_file(actual_filename, actual_contents)
if diff_filename:
cmd = [executable, '--diff', expected_filename,
@@ -171,7 +172,7 @@ class ChromiumPort(base.Port):
else:
raise e
finally:
- shutil.rmtree(tempdir, ignore_errors=True)
+ self._filesystem.rmtree(str(tempdir))
return result
def driver_name(self):
@@ -183,15 +184,15 @@ class ChromiumPort(base.Port):
"""Returns the full path to path made by joining the top of the
Chromium source tree and the list of path components in |*comps|."""
if not self._chromium_base_dir:
- abspath = os.path.abspath(__file__)
+ abspath = self._filesystem.abspath(__file__)
offset = abspath.find('third_party')
if offset == -1:
- self._chromium_base_dir = os.path.join(
+ self._chromium_base_dir = self._filesystem.join(
abspath[0:abspath.find('Tools')],
'WebKit', 'chromium')
else:
self._chromium_base_dir = abspath[0:offset]
- return os.path.join(self._chromium_base_dir, *comps)
+ return self._filesystem.join(self._chromium_base_dir, *comps)
def path_to_test_expectations_file(self):
return self.path_from_webkit_base('LayoutTests', 'platform',
@@ -209,10 +210,10 @@ class ChromiumPort(base.Port):
def setup_test_run(self):
# Delete the disk cache if any to ensure a clean test run.
dump_render_tree_binary_path = self._path_to_driver()
- cachedir = os.path.split(dump_render_tree_binary_path)[0]
- cachedir = os.path.join(cachedir, "cache")
- if os.path.exists(cachedir):
- shutil.rmtree(cachedir)
+ cachedir = self._filesystem.dirname(dump_render_tree_binary_path)
+ cachedir = self._filesystem.join(cachedir, "cache")
+ if self._filesystem.exists(cachedir):
+ self._filesystem.rmtree(cachedir)
def create_driver(self, worker_number):
"""Starts a new Driver and returns a handle to it."""
@@ -249,8 +250,7 @@ class ChromiumPort(base.Port):
Basically this string should contain the equivalent of a
test_expectations file. See test_expectations.py for more details."""
expectations_path = self.path_to_test_expectations_file()
- with codecs.open(expectations_path, "r", "utf-8") as file:
- return file.read()
+ return self._filesystem.read_text_file(expectations_path)
def test_expectations_overrides(self):
try:
@@ -258,10 +258,9 @@ class ChromiumPort(base.Port):
'layout_tests', 'test_expectations.txt')
except AssertionError:
return None
- if not os.path.exists(overrides_path):
+ if not self._filesystem.exists(overrides_path):
return None
- with codecs.open(overrides_path, "r", "utf-8") as file:
- return file.read()
+ return self._filesystem.read_text_file(overrides_path)
def skipped_layout_tests(self, extra_test_files=None):
expectations_str = self.test_expectations()
@@ -310,8 +309,8 @@ class ChromiumPort(base.Port):
debug_path = self._path_to_driver('Debug')
release_path = self._path_to_driver('Release')
- debug_mtime = os.stat(debug_path).st_mtime
- release_mtime = os.stat(release_path).st_mtime
+ debug_mtime = self._filesystem.mtime(debug_path)
+ release_mtime = self._filesystem.mtime(release_path)
if (debug_mtime > release_mtime and configuration == 'Release' or
release_mtime > debug_mtime and configuration == 'Debug'):
@@ -354,7 +353,7 @@ class ChromiumDriver(base.Driver):
self._worker_number = worker_number
self._image_path = None
if self._port.get_option('pixel_tests'):
- self._image_path = os.path.join(
+ self._image_path = self._port._filesystem.join(
self._port.get_option('results_directory'),
'png_result%s.png' % self._worker_number)
@@ -446,9 +445,8 @@ class ChromiumDriver(base.Driver):
def _output_image(self):
"""Returns the image output which driver generated."""
png_path = self._image_path
- if png_path and os.path.isfile(png_path):
- with open(png_path, 'rb') as image_file:
- return image_file.read()
+ if png_path and self._port._filesystem.isfile(png_path):
+ return self._port._filesystem.read_binary_file(png_path)
else:
return None
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py
index c1f5c8d..b88d8aa 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py
@@ -24,10 +24,6 @@
# (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 __future__ import with_statement
-
-import codecs
-import os
import sys
import chromium_linux
@@ -82,10 +78,9 @@ def _gpu_overrides(port):
'layout_tests', 'test_expectations_gpu.txt')
except AssertionError:
return None
- if not os.path.exists(overrides_path):
+ if not port._filesystem.exists(overrides_path):
return None
- with codecs.open(overrides_path, "r", "utf-8") as file:
- return file.read()
+ return port._filesystem.read_text_file(overrides_path)
class ChromiumGpuLinuxPort(chromium_linux.ChromiumLinuxPort):
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py
index ad0404c..0bfb127 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py
@@ -24,7 +24,6 @@
# (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 unittest
from webkitpy.tool import mocktool
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
index 5d9dd87..c1c85f8 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
@@ -78,20 +78,24 @@ class ChromiumLinuxPort(chromium.ChromiumPort):
#
def _build_path(self, *comps):
+ if self.get_option('build_directory'):
+ return self._filesystem.join(self.get_option('build_directory'),
+ *comps)
+
base = self.path_from_chromium_base()
- if os.path.exists(os.path.join(base, 'sconsbuild')):
- return os.path.join(base, 'sconsbuild', *comps)
- if os.path.exists(os.path.join(base, 'out', *comps)) or self.get_option('use_test_shell'):
- return os.path.join(base, 'out', *comps)
+ if self._filesystem.exists(self._filesystem.join(base, 'sconsbuild')):
+ return self._filesystem.join(base, 'sconsbuild', *comps)
+ if self._filesystem.exists(self._filesystem.join(base, 'out', *comps)) or self.get_option('use_test_shell'):
+ return self._filesystem.join(base, 'out', *comps)
base = self.path_from_webkit_base()
- if os.path.exists(os.path.join(base, 'sconsbuild')):
- return os.path.join(base, 'sconsbuild', *comps)
- return os.path.join(base, 'out', *comps)
+ if self._filesystem.exists(self._filesystem.join(base, 'sconsbuild')):
+ return self._filesystem.join(base, 'sconsbuild', *comps)
+ return self._filesystem.join(base, 'out', *comps)
def _check_apache_install(self):
- result = chromium.check_file_exists(self._path_to_apache(),
+ result = self._check_file_exists(self._path_to_apache(),
"apache2")
- result = chromium.check_file_exists(self._path_to_apache_config_file(),
+ result = self._check_file_exists(self._path_to_apache_config_file(),
"apache2 config file") and result
if not result:
_log.error(' Please install using: "sudo apt-get install '
@@ -100,11 +104,11 @@ class ChromiumLinuxPort(chromium.ChromiumPort):
return result
def _check_lighttpd_install(self):
- result = chromium.check_file_exists(
+ result = self._check_file_exists(
self._path_to_lighttpd(), "LigHTTPd executable")
- result = chromium.check_file_exists(self._path_to_lighttpd_php(),
+ result = self._check_file_exists(self._path_to_lighttpd_php(),
"PHP CGI executable") and result
- result = chromium.check_file_exists(self._path_to_lighttpd_modules(),
+ result = self._check_file_exists(self._path_to_lighttpd_modules(),
"LigHTTPd modules") and result
if not result:
_log.error(' Please install using: "sudo apt-get install '
@@ -113,7 +117,7 @@ class ChromiumLinuxPort(chromium.ChromiumPort):
return result
def _check_wdiff_install(self):
- result = chromium.check_file_exists(self._path_to_wdiff(), 'wdiff')
+ result = self._check_file_exists(self._path_to_wdiff(), 'wdiff')
if not result:
_log.error(' Please install using: "sudo apt-get install '
'wdiff"')
@@ -133,7 +137,7 @@ class ChromiumLinuxPort(chromium.ChromiumPort):
else:
config_name = 'apache2-debian-httpd.conf'
- return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf',
config_name)
def _path_to_lighttpd(self):
@@ -163,7 +167,7 @@ class ChromiumLinuxPort(chromium.ChromiumPort):
return '/usr/bin/wdiff'
def _is_redhat_based(self):
- return os.path.exists(os.path.join('/etc', 'redhat-release'))
+ return self._filesystem.exists(self._filesystem.join('/etc', 'redhat-release'))
def _shut_down_http_server(self, server_pid):
"""Shut down the lighttpd web server. Blocks until it's fully
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
index f638e01..5360ab3 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
@@ -105,11 +105,15 @@ class ChromiumMacPort(chromium.ChromiumPort):
#
def _build_path(self, *comps):
+ if self.get_option('build_directory'):
+ return self._filesystem.join(self.get_option('build_directory'),
+ *comps)
+
path = self.path_from_chromium_base('xcodebuild', *comps)
- if os.path.exists(path) or self.get_option('use_test_shell'):
+ if self._filesystem.exists(path) or self.get_option('use_test_shell'):
return path
- return self.path_from_webkit_base('WebKit', 'chromium', 'xcodebuild',
- *comps)
+ return self.path_from_webkit_base(
+ 'Source', 'WebKit', 'chromium', 'xcodebuild', *comps)
def _check_wdiff_install(self):
try:
@@ -128,8 +132,8 @@ class ChromiumMacPort(chromium.ChromiumPort):
return '/usr/sbin/httpd'
def _path_to_apache_config_file(self):
- return os.path.join(self.layout_tests_dir(), 'http', 'conf',
- 'apache2-httpd.conf')
+ return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf',
+ 'apache2-httpd.conf')
def _path_to_lighttpd(self):
return self._lighttpd_path('bin', 'lighttpd')
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py
index c87984f..6c8987b 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py
@@ -26,13 +26,16 @@
# (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 unittest
import StringIO
+from webkitpy.common.system import logtesting
+from webkitpy.common.system import executive_mock
+from webkitpy.common.system import filesystem_mock
from webkitpy.tool import mocktool
from webkitpy.thirdparty.mock import Mock
+
import chromium
import chromium_linux
import chromium_mac
@@ -98,7 +101,8 @@ class ChromiumPortTest(unittest.TestCase):
def __init__(self, options):
chromium_linux.ChromiumLinuxPort.__init__(self,
port_name='test-port',
- options=options)
+ options=options,
+ filesystem=filesystem_mock.MockFileSystem())
def default_configuration(self):
self.default_configuration_called = True
@@ -126,7 +130,7 @@ class ChromiumPortTest(unittest.TestCase):
mock_options = mocktool.MockOptions()
port = ChromiumPortTest.TestLinuxPort(options=mock_options)
- fake_test = os.path.join(port.layout_tests_dir(), "fast/js/not-good.js")
+ fake_test = port._filesystem.join(port.layout_tests_dir(), "fast/js/not-good.js")
port.test_expectations = lambda: """BUG_TEST SKIP : fast/js/not-good.js = TEXT
LINUX WIN : fast/js/very-good.js = TIMEOUT PASS"""
@@ -153,35 +157,19 @@ LINUX WIN : fast/js/very-good.js = TIMEOUT PASS"""
def _path_to_image_diff(self):
return "/path/to/image_diff"
- class MockExecute:
- def __init__(self, result):
- self._result = result
-
- def run_command(self,
- args,
- cwd=None,
- input=None,
- error_handler=None,
- return_exit_code=False,
- return_stderr=True,
- decode_output=False):
- if return_exit_code:
- return self._result
- return ''
-
mock_options = mocktool.MockOptions()
port = ChromiumPortTest.TestLinuxPort(mock_options)
# Images are different.
- port._executive = MockExecute(0)
+ port._executive = executive_mock.MockExecutive2(exit_code=0)
self.assertEquals(False, port.diff_image("EXPECTED", "ACTUAL"))
# Images are the same.
- port._executive = MockExecute(1)
+ port._executive = executive_mock.MockExecutive2(exit_code=1)
self.assertEquals(True, port.diff_image("EXPECTED", "ACTUAL"))
# There was some error running image_diff.
- port._executive = MockExecute(2)
+ port._executive = executive_mock.MockExecutive2(exit_code=2)
exception_raised = False
try:
port.diff_image("EXPECTED", "ACTUAL")
@@ -189,5 +177,25 @@ LINUX WIN : fast/js/very-good.js = TIMEOUT PASS"""
exception_raised = True
self.assertFalse(exception_raised)
+
+class ChromiumPortLoggingTest(logtesting.LoggingTestCase):
+ def test_check_sys_deps(self):
+ mock_options = mocktool.MockOptions()
+ port = ChromiumPortTest.TestLinuxPort(options=mock_options)
+
+ # Success
+ port._executive = executive_mock.MockExecutive2(exit_code=0)
+ self.assertTrue(port.check_sys_deps(needs_http=False))
+
+ # Failure
+ port._executive = executive_mock.MockExecutive2(exit_code=1,
+ output='testing output failure')
+ self.assertFalse(port.check_sys_deps(needs_http=False))
+ self.assertLog([
+ 'ERROR: System dependencies check failed.\n',
+ 'ERROR: To override, invoke with --nocheck-sys-deps\n',
+ 'ERROR: \n',
+ 'ERROR: testing output failure\n'])
+
if __name__ == '__main__':
unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py
index d080f82..14f2777 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py
@@ -30,7 +30,6 @@
"""Chromium Win implementation of the Port interface."""
import logging
-import os
import sys
import chromium
@@ -106,14 +105,17 @@ class ChromiumWinPort(chromium.ChromiumPort):
# PROTECTED ROUTINES
#
def _build_path(self, *comps):
+ if self.get_option('build_directory'):
+ return self._filesystem.join(self.get_option('build_directory'),
+ *comps)
+
p = self.path_from_chromium_base('webkit', *comps)
- if os.path.exists(p):
+ if self._filesystem.exists(p):
return p
p = self.path_from_chromium_base('chrome', *comps)
- if os.path.exists(p) or self.get_option('use_test_shell'):
+ if self._filesystem.exists(p) or self.get_option('use_test_shell'):
return p
- return os.path.join(self.path_from_webkit_base(), 'WebKit', 'chromium',
- *comps)
+ return self._filesystem.join(self.path_from_webkit_base(), 'WebKit', 'chromium', *comps)
def _lighttpd_path(self, *comps):
return self.path_from_chromium_base('third_party', 'lighttpd', 'win',
@@ -124,8 +126,7 @@ class ChromiumWinPort(chromium.ChromiumPort):
'sbin', 'httpd')
def _path_to_apache_config_file(self):
- return os.path.join(self.layout_tests_dir(), 'http', 'conf',
- 'cygwin-httpd.conf')
+ return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', 'cygwin-httpd.conf')
def _path_to_lighttpd(self):
return self._lighttpd_path('LightTPD.exe')
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py
index 36f3c6b..d677589 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py
@@ -45,13 +45,15 @@ class ChromiumWinTest(unittest.TestCase):
def tearDown(self):
sys.platform = self.orig_platform
+ self._port = None
def _mock_path_from_chromium_base(self, *comps):
- return os.path.join("/chromium/src", *comps)
+ return self._port._filesystem.join("/chromium/src", *comps)
def test_setup_environ_for_server(self):
port = chromium_win.ChromiumWinPort()
port._executive = mocktool.MockExecutive(should_log=True)
+ self._port = port
port.path_from_chromium_base = self._mock_path_from_chromium_base
output = outputcapture.OutputCapture()
orig_environ = os.environ.copy()
@@ -65,6 +67,7 @@ class ChromiumWinTest(unittest.TestCase):
options=ChromiumWinTest.RegisterCygwinOption())
port._executive = mocktool.MockExecutive(should_log=True)
port.path_from_chromium_base = self._mock_path_from_chromium_base
+ self._port = port
setup_mount = self._mock_path_from_chromium_base("third_party",
"cygwin",
"setup_mount.bat")
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/config.py b/Tools/Scripts/webkitpy/layout_tests/port/config.py
index e08ed9d..6016639 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/config.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/config.py
@@ -32,8 +32,6 @@
# FIXME: This file needs to be unified with common/checkout/scm.py and
# common/config/ports.py .
-import os
-
from webkitpy.common.system import logutils
from webkitpy.common.system import executive
@@ -131,7 +129,7 @@ class Config(object):
#
# This code will also work if there is no SCM system at all.
if not self._webkit_base_dir:
- abspath = os.path.abspath(__file__)
+ abspath = self._filesystem.abspath(__file__)
self._webkit_base_dir = abspath[0:abspath.find('Tools') - 1]
return self._webkit_base_dir
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/google_chrome.py b/Tools/Scripts/webkitpy/layout_tests/port/google_chrome.py
index 8d94bb5..ae90374 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/google_chrome.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/google_chrome.py
@@ -24,11 +24,6 @@
# (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 __future__ import with_statement
-
-import codecs
-import os
-
def _test_expectations_overrides(port, super):
# The chrome ports use the regular overrides plus anything in the
@@ -40,14 +35,11 @@ def _test_expectations_overrides(port, super):
# this changed in r60427. This should probably be changed back.
overrides_path = port.path_from_chromium_base('webkit', 'tools',
'layout_tests', 'test_expectations_chrome.txt')
- if not os.path.exists(overrides_path):
+ if not port._filesystem.exists(overrides_path):
return chromium_overrides
- with codecs.open(overrides_path, "r", "utf-8") as file:
- if chromium_overrides:
- return chromium_overrides + file.read()
- else:
- return file.read()
+ chromium_overrides = chromium_overrides or ''
+ return chromium_overrides + port._filesystem.read_text_file(overrides_path)
def GetGoogleChromePort(**kwargs):
"""Some tests have slightly different results when compiled as Google
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py
index e60c274..aab8dd1 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py
@@ -24,11 +24,9 @@
# (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 codecs
-import os
import unittest
-from webkitpy.common import newstringio
+from webkitpy.common.system import filesystem_mock
import factory
import google_chrome
@@ -50,7 +48,7 @@ class GetGoogleChromePortTest(unittest.TestCase):
port = google_chrome.GetGoogleChromePort(port_name=port_name,
options=None)
path = port.baseline_search_path()[0]
- self.assertEqual(expected_path, os.path.split(path)[1])
+ self.assertEqual(expected_path, port._filesystem.basename(path))
def _verify_expectations_overrides(self, port_name):
# FIXME: make this more robust when we have the Tree() abstraction.
@@ -58,45 +56,27 @@ class GetGoogleChromePortTest(unittest.TestCase):
# be able to control the contents better.
chromium_port = factory.get("chromium-mac")
- chromium_overrides = chromium_port.test_expectations_overrides()
+ chromium_base = chromium_port.path_from_chromium_base()
+ fs = filesystem_mock.MockFileSystem()
port = google_chrome.GetGoogleChromePort(port_name=port_name,
- options=None)
-
- orig_exists = os.path.exists
- orig_open = codecs.open
- expected_string = "// hello, world\n"
-
- def mock_exists_chrome_not_found(path):
- if 'test_expectations_chrome.txt' in path:
- return False
- return orig_exists(path)
-
- def mock_exists_chrome_found(path):
- if 'test_expectations_chrome.txt' in path:
- return True
- return orig_exists(path)
-
- def mock_open(path, mode, encoding):
- if 'test_expectations_chrome.txt' in path:
- return newstringio.StringIO(expected_string)
- return orig_open(path, mode, encoding)
-
- try:
- os.path.exists = mock_exists_chrome_not_found
- chrome_overrides = port.test_expectations_overrides()
- self.assertEqual(chromium_overrides, chrome_overrides)
-
- os.path.exists = mock_exists_chrome_found
- codecs.open = mock_open
- chrome_overrides = port.test_expectations_overrides()
- if chromium_overrides:
- self.assertEqual(chrome_overrides,
- chromium_overrides + expected_string)
- else:
- self.assertEqual(chrome_overrides, expected_string)
- finally:
- os.path.exists = orig_exists
- codecs.open = orig_open
+ options=None, filesystem=fs)
+
+ expected_chromium_overrides = '// chromium overrides\n'
+ expected_chrome_overrides = '// chrome overrides\n'
+ chromium_path = fs.join(chromium_base, 'webkit', 'tools',
+ 'layout_tests', 'test_expectations.txt')
+ chrome_path = fs.join(chromium_base, 'webkit', 'tools',
+ 'layout_tests', 'test_expectations_chrome.txt')
+
+ fs.files[chromium_path] = expected_chromium_overrides
+ fs.files[chrome_path] = None
+ actual_chrome_overrides = port.test_expectations_overrides()
+ self.assertEqual(expected_chromium_overrides, actual_chrome_overrides)
+
+ fs.files[chrome_path] = expected_chrome_overrides
+ actual_chrome_overrides = port.test_expectations_overrides()
+ self.assertEqual(actual_chrome_overrides,
+ expected_chromium_overrides + expected_chrome_overrides)
if __name__ == '__main__':
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/gtk.py b/Tools/Scripts/webkitpy/layout_tests/port/gtk.py
index a18fdff..0ec9f87 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/gtk.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/gtk.py
@@ -57,8 +57,8 @@ class GtkPort(WebKitPort):
def _path_to_apache_config_file(self):
# FIXME: This needs to detect the distribution and change config files.
- return os.path.join(self.layout_tests_dir(), 'http', 'conf',
- 'apache2-debian-httpd.conf')
+ return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf',
+ 'apache2-debian-httpd.conf')
def _shut_down_http_server(self, server_pid):
"""Shut down the httpd web server. Blocks until it's fully
@@ -103,7 +103,7 @@ class GtkPort(WebKitPort):
else:
config_name = 'apache2-debian-httpd.conf'
- return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf',
config_name)
def _path_to_wdiff(self):
@@ -113,4 +113,4 @@ class GtkPort(WebKitPort):
return '/usr/bin/wdiff'
def _is_redhat_based(self):
- return os.path.exists(os.path.join('/etc', 'redhat-release'))
+ return self._filesystem.exists(self._filesystem.join('/etc', 'redhat-release'))
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mac.py b/Tools/Scripts/webkitpy/layout_tests/port/mac.py
index 696e339..0622196 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/mac.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/mac.py
@@ -76,9 +76,9 @@ class MacPort(WebKitPort):
# platforms and moved into base.Port.
skipped_files = []
if self._name in ('mac-tiger', 'mac-leopard', 'mac-snowleopard'):
- skipped_files.append(os.path.join(
+ skipped_files.append(self._filesystem.join(
self._webkit_baseline_path(self._name), 'Skipped'))
- skipped_files.append(os.path.join(self._webkit_baseline_path('mac'),
+ skipped_files.append(self._filesystem.join(self._webkit_baseline_path('mac'),
'Skipped'))
return skipped_files
@@ -99,7 +99,7 @@ class MacPort(WebKitPort):
return ''
def _build_java_test_support(self):
- java_tests_path = os.path.join(self.layout_tests_dir(), "java")
+ java_tests_path = self._filesystem.join(self.layout_tests_dir(), "java")
build_java = ["/usr/bin/make", "-C", java_tests_path]
if self._executive.run_command(build_java, return_exit_code=True):
_log.error("Failed to build Java support files: %s" % build_java)
@@ -124,8 +124,8 @@ class MacPort(WebKitPort):
]
def _path_to_apache_config_file(self):
- return os.path.join(self.layout_tests_dir(), 'http', 'conf',
- 'apache2-httpd.conf')
+ return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf',
+ 'apache2-httpd.conf')
# FIXME: This doesn't have anything to do with WebKit.
def _shut_down_http_server(self, server_pid):
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py b/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
index c4b36ac..0b03b4c 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
@@ -28,8 +28,6 @@
"""Unit testing base class for Port implementations."""
-import os
-import tempfile
import unittest
from webkitpy.tool import mocktool
@@ -52,44 +50,39 @@ class PortTestCase(unittest.TestCase):
return
self.assertTrue(len(port.driver_cmd_line()))
- def test_http_server(self):
+ def disabled_test_http_server(self):
port = self.make_port()
if not port:
return
port.start_http_server()
port.stop_http_server()
- def test_image_diff(self):
+ def disabled_test_image_diff(self):
port = self.make_port()
if not port:
return
- # FIXME: not sure why this shouldn't always be True
- #self.assertTrue(port.check_image_diff())
if not port.check_image_diff():
+ # The port hasn't been built - don't run the tests.
return
dir = port.layout_tests_dir()
- file1 = os.path.join(dir, 'fast', 'css', 'button_center.png')
- fh1 = file(file1)
- contents1 = fh1.read()
- file2 = os.path.join(dir, 'fast', 'css',
- 'remove-shorthand-expected.png')
- fh2 = file(file2)
- contents2 = fh2.read()
- tmpfile = tempfile.mktemp()
+ file1 = port._filesystem.join(dir, 'fast', 'css', 'button_center.png')
+ contents1 = port._filesystem.read_binary_file(file1)
+ file2 = port._filesystem.join(dir, 'fast', 'css',
+ 'remove-shorthand-expected.png')
+ contents2 = port._filesystem.read_binary_file(file2)
+ tmpfd, tmpfile = port._filesystem.open_binary_tempfile('')
+ tmpfd.close()
self.assertFalse(port.diff_image(contents1, contents1))
self.assertTrue(port.diff_image(contents1, contents2))
self.assertTrue(port.diff_image(contents1, contents2, tmpfile))
- fh1.close()
- fh2.close()
- # FIXME: this may not be being written?
- # self.assertTrue(os.path.exists(tmpfile))
- # os.remove(tmpfile)
- def test_websocket_server(self):
+ port._filesystem.remove(tmpfile)
+
+ def disabled_test_websocket_server(self):
port = self.make_port()
if not port:
return
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/qt.py b/Tools/Scripts/webkitpy/layout_tests/port/qt.py
index af94acc..1695b60 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/qt.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/qt.py
@@ -71,8 +71,8 @@ class QtPort(WebKitPort):
def _path_to_apache_config_file(self):
# FIXME: This needs to detect the distribution and change config files.
- return os.path.join(self.layout_tests_dir(), 'http', 'conf',
- 'apache2-debian-httpd.conf')
+ return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf',
+ 'apache2-debian-httpd.conf')
def _shut_down_http_server(self, server_pid):
"""Shut down the httpd web server. Blocks until it's fully
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test.py b/Tools/Scripts/webkitpy/layout_tests/port/test.py
index 935881c..5df5c2d 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/test.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/test.py
@@ -30,12 +30,10 @@
"""Dummy Port implementation used for testing."""
from __future__ import with_statement
-import codecs
-import fnmatch
-import os
-import sys
import time
+from webkitpy.common.system import filesystem_mock
+
from webkitpy.layout_tests.layout_package import test_output
import base
@@ -64,8 +62,7 @@ class TestInstance:
# This is an in-memory list of tests, what we want them to produce, and
# what we want to claim are the expected results.
class TestList:
- def __init__(self, port):
- self.port = port
+ def __init__(self):
self.tests = {}
def add(self, name, **kwargs):
@@ -84,66 +81,141 @@ class TestList:
return self.tests[item]
+def unit_test_list():
+ tests = TestList()
+ tests.add('failures/expected/checksum.html',
+ actual_checksum='checksum_fail-checksum')
+ tests.add('failures/expected/crash.html', crash=True)
+ tests.add('failures/expected/exception.html', exception=True)
+ tests.add('failures/expected/timeout.html', timeout=True)
+ tests.add('failures/expected/hang.html', hang=True)
+ tests.add('failures/expected/missing_text.html',
+ expected_text=None)
+ tests.add('failures/expected/image.html',
+ actual_image='image_fail-png',
+ expected_image='image-png')
+ tests.add('failures/expected/image_checksum.html',
+ actual_checksum='image_checksum_fail-checksum',
+ actual_image='image_checksum_fail-png')
+ tests.add('failures/expected/keyboard.html',
+ keyboard=True)
+ tests.add('failures/expected/missing_check.html',
+ expected_checksum=None)
+ tests.add('failures/expected/missing_image.html',
+ expected_image=None)
+ tests.add('failures/expected/missing_text.html',
+ expected_text=None)
+ tests.add('failures/expected/newlines_leading.html',
+ expected_text="\nfoo\n",
+ actual_text="foo\n")
+ tests.add('failures/expected/newlines_trailing.html',
+ expected_text="foo\n\n",
+ actual_text="foo\n")
+ tests.add('failures/expected/newlines_with_excess_CR.html',
+ expected_text="foo\r\r\r\n",
+ actual_text="foo\n")
+ tests.add('failures/expected/text.html',
+ actual_text='text_fail-png')
+ tests.add('failures/unexpected/crash.html', crash=True)
+ tests.add('failures/unexpected/text-image-checksum.html',
+ actual_text='text-image-checksum_fail-txt',
+ actual_checksum='text-image-checksum_fail-checksum')
+ tests.add('failures/unexpected/timeout.html', timeout=True)
+ tests.add('http/tests/passes/text.html')
+ tests.add('http/tests/ssl/text.html')
+ tests.add('passes/error.html', error='stuff going to stderr')
+ tests.add('passes/image.html')
+ tests.add('passes/platform_image.html')
+ # Text output files contain "\r\n" on Windows. This may be
+ # helpfully filtered to "\r\r\n" by our Python/Cygwin tooling.
+ tests.add('passes/text.html',
+ expected_text='\nfoo\n\n',
+ actual_text='\nfoo\r\n\r\r\n')
+ tests.add('websocket/tests/passes/text.html')
+ return tests
+
+
+# Here we use a non-standard location for the layout tests, to ensure that
+# this works. The path contains a '.' in the name because we've seen bugs
+# related to this before.
+
+LAYOUT_TEST_DIR = '/test.checkout/LayoutTests'
+
+
+# Here we synthesize an in-memory filesystem from the test list
+# in order to fully control the test output and to demonstrate that
+# we don't need a real filesystem to run the tests.
+
+def unit_test_filesystem(files=None):
+ """Return the FileSystem object used by the unit tests."""
+ test_list = unit_test_list()
+ files = files or {}
+
+ def add_file(files, test, suffix, contents):
+ dirname = test.name[0:test.name.rfind('/')]
+ base = test.base
+ path = LAYOUT_TEST_DIR + '/' + dirname + '/' + base + suffix
+ files[path] = contents
+
+ # Add each test and the expected output, if any.
+ for test in test_list.tests.values():
+ add_file(files, test, '.html', '')
+ add_file(files, test, '-expected.txt', test.expected_text)
+ add_file(files, test, '-expected.checksum', test.expected_checksum)
+ add_file(files, test, '-expected.png', test.expected_image)
+
+ # Add the test_expectations file.
+ files[LAYOUT_TEST_DIR + '/platform/test/test_expectations.txt'] = """
+WONTFIX : failures/expected/checksum.html = IMAGE
+WONTFIX : failures/expected/crash.html = CRASH
+// This one actually passes because the checksums will match.
+WONTFIX : failures/expected/image.html = PASS
+WONTFIX : failures/expected/image_checksum.html = IMAGE
+WONTFIX : failures/expected/missing_check.html = MISSING PASS
+WONTFIX : failures/expected/missing_image.html = MISSING PASS
+WONTFIX : failures/expected/missing_text.html = MISSING PASS
+WONTFIX : failures/expected/newlines_leading.html = TEXT
+WONTFIX : failures/expected/newlines_trailing.html = TEXT
+WONTFIX : failures/expected/newlines_with_excess_CR.html = TEXT
+WONTFIX : failures/expected/text.html = TEXT
+WONTFIX : failures/expected/timeout.html = TIMEOUT
+WONTFIX SKIP : failures/expected/hang.html = TIMEOUT
+WONTFIX SKIP : failures/expected/keyboard.html = CRASH
+WONTFIX SKIP : failures/expected/exception.html = CRASH
+"""
+
+ fs = filesystem_mock.MockFileSystem(files)
+ fs._tests = test_list
+ return fs
+
+
class TestPort(base.Port):
"""Test implementation of the Port interface."""
def __init__(self, **kwargs):
+ # FIXME: what happens if we're not passed in the test filesystem
+ # and the tests don't match what's in the filesystem?
+ #
+ # We'll leave as is for now to avoid unnecessary dependencies while
+ # converting all of the unit tests over to using
+ # unit_test_filesystem(). If things get out of sync the tests should
+ # fail in fairly obvious ways. Eventually we want to just do:
+ #
+ # assert kwargs['filesystem']._tests
+ # self._tests = kwargs['filesystem']._tests
+
+ if 'filesystem' not in kwargs or kwargs['filesystem'] is None:
+ kwargs['filesystem'] = unit_test_filesystem()
+ self._tests = kwargs['filesystem']._tests
+ else:
+ self._tests = unit_test_list()
+
+ kwargs.setdefault('port_name', 'test')
base.Port.__init__(self, **kwargs)
- tests = TestList(self)
- tests.add('failures/expected/checksum.html',
- actual_checksum='checksum_fail-checksum')
- tests.add('failures/expected/crash.html', crash=True)
- tests.add('failures/expected/exception.html', exception=True)
- tests.add('failures/expected/timeout.html', timeout=True)
- tests.add('failures/expected/hang.html', hang=True)
- tests.add('failures/expected/missing_text.html',
- expected_text=None)
- tests.add('failures/expected/image.html',
- actual_image='image_fail-png',
- expected_image='image-png')
- tests.add('failures/expected/image_checksum.html',
- actual_checksum='image_checksum_fail-checksum',
- actual_image='image_checksum_fail-png')
- tests.add('failures/expected/keyboard.html',
- keyboard=True)
- tests.add('failures/expected/missing_check.html',
- expected_checksum=None)
- tests.add('failures/expected/missing_image.html',
- expected_image=None)
- tests.add('failures/expected/missing_text.html',
- expected_text=None)
- tests.add('failures/expected/newlines_leading.html',
- expected_text="\nfoo\n",
- actual_text="foo\n")
- tests.add('failures/expected/newlines_trailing.html',
- expected_text="foo\n\n",
- actual_text="foo\n")
- tests.add('failures/expected/newlines_with_excess_CR.html',
- expected_text="foo\r\r\r\n",
- actual_text="foo\n")
- tests.add('failures/expected/text.html',
- actual_text='text_fail-png')
- tests.add('failures/unexpected/crash.html', crash=True)
- tests.add('failures/unexpected/text-image-checksum.html',
- actual_text='text-image-checksum_fail-txt',
- actual_checksum='text-image-checksum_fail-checksum')
- tests.add('failures/unexpected/timeout.html', timeout=True)
- tests.add('http/tests/passes/text.html')
- tests.add('http/tests/ssl/text.html')
- tests.add('passes/error.html', error='stuff going to stderr')
- tests.add('passes/image.html')
- tests.add('passes/platform_image.html')
- # Text output files contain "\r\n" on Windows. This may be
- # helpfully filtered to "\r\r\n" by our Python/Cygwin tooling.
- tests.add('passes/text.html',
- expected_text='\nfoo\n\n',
- actual_text='\nfoo\r\n\r\r\n')
- tests.add('websocket/tests/passes/text.html')
- self._tests = tests
def baseline_path(self):
- return os.path.join(self.layout_tests_dir(), 'platform',
- self.name() + self.version())
+ return self._filesystem.join(self.layout_tests_dir(), 'platform',
+ self.name() + self.version())
def baseline_search_path(self):
return [self.baseline_path()]
@@ -155,92 +227,12 @@ class TestPort(base.Port):
diff_filename=None):
diffed = actual_contents != expected_contents
if diffed and diff_filename:
- with codecs.open(diff_filename, "w", "utf-8") as diff_fh:
- diff_fh.write("< %s\n---\n> %s\n" %
- (expected_contents, actual_contents))
+ self._filesystem.write_text_file(diff_filename,
+ "< %s\n---\n> %s\n" % (expected_contents, actual_contents))
return diffed
- def expected_checksum(self, test):
- test = self.relative_test_filename(test)
- return self._tests[test].expected_checksum
-
- def expected_image(self, test):
- test = self.relative_test_filename(test)
- return self._tests[test].expected_image
-
- def expected_text(self, test):
- test = self.relative_test_filename(test)
- text = self._tests[test].expected_text
- if not text:
- text = ''
- return text
-
- def tests(self, paths):
- # Test the idea of port-specific overrides for test lists. Also
- # keep in memory to speed up the test harness.
- if not paths:
- paths = ['*']
-
- matched_tests = []
- for p in paths:
- if self.path_isdir(p):
- matched_tests.extend(fnmatch.filter(self._tests.keys(), p + '*'))
- else:
- matched_tests.extend(fnmatch.filter(self._tests.keys(), p))
- layout_tests_dir = self.layout_tests_dir()
- return set([os.path.join(layout_tests_dir, p) for p in matched_tests])
-
- def path_exists(self, path):
- # used by test_expectations.py and printing.py
- rpath = self.relative_test_filename(path)
- if rpath in self._tests:
- return True
- if self.path_isdir(rpath):
- return True
- if rpath.endswith('-expected.txt'):
- test = rpath.replace('-expected.txt', '.html')
- return (test in self._tests and
- self._tests[test].expected_text)
- if rpath.endswith('-expected.checksum'):
- test = rpath.replace('-expected.checksum', '.html')
- return (test in self._tests and
- self._tests[test].expected_checksum)
- if rpath.endswith('-expected.png'):
- test = rpath.replace('-expected.png', '.html')
- return (test in self._tests and
- self._tests[test].expected_image)
- return False
-
def layout_tests_dir(self):
- return self.path_from_webkit_base('Tools', 'Scripts',
- 'webkitpy', 'layout_tests', 'data')
-
- def path_isdir(self, path):
- # Used by test_expectations.py
- #
- # We assume that a path is a directory if we have any tests
- # that whose prefix matches the path plus a directory modifier
- # and not a file extension.
- if path[-1] != '/':
- path += '/'
-
- # FIXME: Directories can have a dot in the name. We should
- # probably maintain a white list of known cases like CSS2.1
- # and check it here in the future.
- if path.find('.') != -1:
- # extension separator found, assume this is a file
- return False
-
- # strip out layout tests directory path if found. The tests
- # keys are relative to it.
- tests_dir = self.layout_tests_dir()
- if path.startswith(tests_dir):
- path = path[len(tests_dir) + 1:]
-
- return any([t.startswith(path) for t in self._tests.keys()])
-
- def test_dirs(self):
- return ['passes', 'failures']
+ return LAYOUT_TEST_DIR
def name(self):
return self._name
@@ -269,33 +261,12 @@ class TestPort(base.Port):
def stop_websocket_server(self):
pass
- def test_expectations(self):
- """Returns the test expectations for this port.
-
- Basically this string should contain the equivalent of a
- test_expectations file. See test_expectations.py for more details."""
- return """
-WONTFIX : failures/expected/checksum.html = IMAGE
-WONTFIX : failures/expected/crash.html = CRASH
-// This one actually passes because the checksums will match.
-WONTFIX : failures/expected/image.html = PASS
-WONTFIX : failures/expected/image_checksum.html = IMAGE
-WONTFIX : failures/expected/missing_check.html = MISSING PASS
-WONTFIX : failures/expected/missing_image.html = MISSING PASS
-WONTFIX : failures/expected/missing_text.html = MISSING PASS
-WONTFIX : failures/expected/newlines_leading.html = TEXT
-WONTFIX : failures/expected/newlines_trailing.html = TEXT
-WONTFIX : failures/expected/newlines_with_excess_CR.html = TEXT
-WONTFIX : failures/expected/text.html = TEXT
-WONTFIX : failures/expected/timeout.html = TIMEOUT
-WONTFIX SKIP : failures/expected/hang.html = TIMEOUT
-WONTFIX SKIP : failures/expected/keyboard.html = CRASH
-WONTFIX SKIP : failures/expected/exception.html = CRASH
-"""
-
def test_base_platform_names(self):
return ('mac', 'win')
+ def test_expectations(self):
+ return self._filesystem.read_text_file(LAYOUT_TEST_DIR + '/platform/test/test_expectations.txt')
+
def test_platform_name(self):
return 'mac'
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test_files.py b/Tools/Scripts/webkitpy/layout_tests/port/test_files.py
index 2c0a7b6..41d918f 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/test_files.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/test_files.py
@@ -34,8 +34,6 @@ list of test files is constrained to those found under the paths passed in,
i.e. calling find(["LayoutTests/fast"]) will only return files
under that directory."""
-import glob
-import os
import time
from webkitpy.common.system import logutils
@@ -58,16 +56,18 @@ def find(port, paths):
paths: a list of command line paths relative to the layout_tests_dir()
to limit the search to. glob patterns are ok.
"""
+ fs = port._filesystem
gather_start_time = time.time()
paths_to_walk = set()
+
# if paths is empty, provide a pre-defined list.
if paths:
_log.debug("Gathering tests from: %s relative to %s" % (paths, port.layout_tests_dir()))
for path in paths:
# If there's an * in the name, assume it's a glob pattern.
- path = os.path.join(port.layout_tests_dir(), path)
+ path = fs.join(port.layout_tests_dir(), path)
if path.find('*') > -1:
- filenames = glob.glob(path)
+ filenames = fs.glob(path)
paths_to_walk.update(filenames)
else:
paths_to_walk.add(path)
@@ -75,30 +75,12 @@ def find(port, paths):
_log.debug("Gathering tests from: %s" % port.layout_tests_dir())
paths_to_walk.add(port.layout_tests_dir())
- # Now walk all the paths passed in on the command line and get filenames
+ # FIXME: I'm not sure there's much point in this being a set. A list would
+ # probably be faster.
test_files = set()
for path in paths_to_walk:
- if os.path.isfile(path) and _is_test_file(path):
- test_files.add(os.path.normpath(path))
- continue
-
- for root, dirs, files in os.walk(path):
- # Don't walk skipped directories or their sub-directories.
- if os.path.basename(root) in _skipped_directories:
- del dirs[:]
- continue
- # This copy and for-in is slightly inefficient, but
- # the extra walk avoidance consistently shaves .5 seconds
- # off of total walk() time on my MacBook Pro.
- for directory in dirs[:]:
- if directory in _skipped_directories:
- dirs.remove(directory)
-
- for filename in files:
- if _is_test_file(filename):
- filename = os.path.join(root, filename)
- filename = os.path.normpath(filename)
- test_files.add(filename)
+ files = fs.files_under(path, _skipped_directories, _is_test_file)
+ test_files.update(set(files))
gather_time = time.time() - gather_start_time
_log.debug("Test gathering took %f seconds" % gather_time)
@@ -106,10 +88,10 @@ def find(port, paths):
return test_files
-def _has_supported_extension(filename):
+def _has_supported_extension(fs, filename):
"""Return true if filename is one of the file extensions we want to run a
test on."""
- extension = os.path.splitext(filename)[1]
+ extension = fs.splitext(filename)[1]
return extension in _supported_file_extensions
@@ -122,7 +104,7 @@ def _is_reference_html_file(filename):
return False
-def _is_test_file(filename):
+def _is_test_file(fs, dirname, filename):
"""Return true if the filename points to a test file."""
- return (_has_supported_extension(filename) and
+ return (_has_supported_extension(fs, filename) and
not _is_reference_html_file(filename))
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py
index 83525c8..a68950a 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py
@@ -26,7 +26,6 @@
# (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 unittest
import base
@@ -37,8 +36,8 @@ class TestFilesTest(unittest.TestCase):
def test_find_no_paths_specified(self):
port = base.Port()
layout_tests_dir = port.layout_tests_dir()
- port.layout_tests_dir = lambda: os.path.join(layout_tests_dir,
- 'fast', 'html')
+ port.layout_tests_dir = lambda: port._filesystem.join(layout_tests_dir,
+ 'fast', 'html')
tests = test_files.find(port, [])
self.assertNotEqual(tests, 0)
@@ -64,11 +63,13 @@ class TestFilesTest(unittest.TestCase):
self.assertEqual(tests, set([]))
def test_is_test_file(self):
- self.assertTrue(test_files._is_test_file('foo.html'))
- self.assertTrue(test_files._is_test_file('foo.shtml'))
- self.assertFalse(test_files._is_test_file('foo.png'))
- self.assertFalse(test_files._is_test_file('foo-expected.html'))
- self.assertFalse(test_files._is_test_file('foo-expected-mismatch.html'))
+ port = base.Port()
+ fs = port._filesystem
+ self.assertTrue(test_files._is_test_file(fs, '', 'foo.html'))
+ self.assertTrue(test_files._is_test_file(fs, '', 'foo.shtml'))
+ self.assertFalse(test_files._is_test_file(fs, '', 'foo.png'))
+ self.assertFalse(test_files._is_test_file(fs, '', 'foo-expected.html'))
+ self.assertFalse(test_files._is_test_file(fs, '', 'foo-expected-mismatch.html'))
if __name__ == '__main__':
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py
index afdebeb..577acd4 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py
@@ -31,20 +31,14 @@
"""WebKit implementations of the Port interface."""
-from __future__ import with_statement
-
-import codecs
import logging
+import operator
import os
import re
-import shutil
import signal
import sys
import time
import webbrowser
-import operator
-import tempfile
-import shutil
import webkitpy.common.system.ospath as ospath
import webkitpy.layout_tests.layout_package.test_output as test_output
@@ -72,8 +66,8 @@ class WebKitPort(base.Port):
return [self._webkit_baseline_path(self._name)]
def path_to_test_expectations_file(self):
- return os.path.join(self._webkit_baseline_path(self._name),
- 'test_expectations.txt')
+ return self._filesystem.join(self._webkit_baseline_path(self._name),
+ 'test_expectations.txt')
# Only needed by ports which maintain versioned test expectations (like mac-tiger vs. mac-leopard)
def version(self):
@@ -85,7 +79,7 @@ class WebKitPort(base.Port):
def _check_driver(self):
driver_path = self._path_to_driver()
- if not os.path.exists(driver_path):
+ if not self._filesystem.exists(driver_path):
_log.error("DumpRenderTree was not found at %s" % driver_path)
return False
return True
@@ -108,7 +102,7 @@ class WebKitPort(base.Port):
def check_image_diff(self, override_step=None, logging=True):
image_diff_path = self._path_to_image_diff()
- if not os.path.exists(image_diff_path):
+ if not self._filesystem.exists(image_diff_path):
_log.error("ImageDiff was not found at %s" % image_diff_path)
return False
return True
@@ -165,8 +159,7 @@ class WebKitPort(base.Port):
if m.group(2) == 'passed':
result = False
elif output and diff_filename:
- with open(diff_filename, 'w') as file:
- file.write(output)
+ self._filesystem.write_text_file(diff_filename, output)
elif sp.timed_out:
_log.error("ImageDiff timed out")
elif sp.crashed:
@@ -300,25 +293,22 @@ class WebKitPort(base.Port):
return tests_to_skip
def _skipped_file_paths(self):
- return [os.path.join(self._webkit_baseline_path(self._name),
- 'Skipped')]
+ return [self._filesystem.join(self._webkit_baseline_path(self._name), 'Skipped')]
def _expectations_from_skipped_files(self):
tests_to_skip = []
for filename in self._skipped_file_paths():
- if not os.path.exists(filename):
+ if not self._filesystem.exists(filename):
_log.warn("Failed to open Skipped file: %s" % filename)
continue
- with codecs.open(filename, "r", "utf-8") as skipped_file:
- tests_to_skip.extend(self._tests_from_skipped_file(skipped_file))
+ skipped_file = self._filesystem.read_text_file(filename)
return tests_to_skip
def test_expectations(self):
# The WebKit mac port uses a combination of a test_expectations file
# and 'Skipped' files.
expectations_path = self.path_to_test_expectations_file()
- with codecs.open(expectations_path, "r", "utf-8") as file:
- return file.read() + self._skips()
+ return self._filesystem.read_text_file(expectations_path) + self._skips()
def _skips(self):
# Each Skipped file contains a list of files
@@ -373,7 +363,7 @@ class WebKitPort(base.Port):
# 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 os.path.exists(path):
+ if self._filesystem.exists(path):
self._cached_apache_path = path
break
@@ -389,10 +379,10 @@ class WebKitDriver(base.Driver):
def __init__(self, port, worker_number):
self._worker_number = worker_number
self._port = port
- self._driver_tempdir = tempfile.mkdtemp(prefix='DumpRenderTree-')
+ self._driver_tempdir = port._filesystem.mkdtemp(prefix='DumpRenderTree-')
def __del__(self):
- shutil.rmtree(self._driver_tempdir)
+ self._port._filesystem.rmtree(str(self._driver_tempdir))
def cmd_line(self):
cmd = self._command_wrapper(self._port.get_option('wrapper'))
@@ -406,7 +396,7 @@ class WebKitDriver(base.Driver):
def start(self):
environment = self._port.setup_environ_for_server()
environment['DYLD_FRAMEWORK_PATH'] = self._port._build_path()
- environment['DUMPRENDERTREE_TEMP'] = self._driver_tempdir
+ environment['DUMPRENDERTREE_TEMP'] = str(self._driver_tempdir)
self._server_process = server_process.ServerProcess(self._port,
"DumpRenderTree", self.cmd_line(), environment)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/win.py b/Tools/Scripts/webkitpy/layout_tests/port/win.py
index 9e30155..e7d2004 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/win.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/win.py
@@ -29,7 +29,6 @@
"""WebKit Win implementation of the Port interface."""
import logging
-import os
from webkitpy.layout_tests.port.webkit import WebKitPort
@@ -60,8 +59,8 @@ class WinPort(WebKitPort):
]
def _path_to_apache_config_file(self):
- return os.path.join(self.layout_tests_dir(), 'http', 'conf',
- 'cygwin-httpd.conf')
+ return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf',
+ 'cygwin-httpd.conf')
def _shut_down_http_server(self, server_pid):
"""Shut down the httpd web server. Blocks until it's fully
diff --git a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py
index 4d8b7c9..c852186 100644
--- a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py
+++ b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py
@@ -41,26 +41,18 @@ The script does the following for each platform specified:
At the end, the script generates a html that compares old and new baselines.
"""
-from __future__ import with_statement
-
-import codecs
import copy
import logging
import optparse
-import os
import re
-import shutil
-import subprocess
import sys
-import tempfile
import time
import urllib
import zipfile
+from webkitpy.common.checkout import scm
from webkitpy.common.system import path
-from webkitpy.common.system import user
-from webkitpy.common.system.executive import Executive, ScriptError
-import webkitpy.common.checkout.scm as scm
+from webkitpy.common.system.executive import ScriptError
import port
from layout_package import test_expectations
@@ -70,16 +62,16 @@ _log = logging.getLogger("webkitpy.layout_tests."
BASELINE_SUFFIXES = ['.txt', '.png', '.checksum']
REBASELINE_PLATFORM_ORDER = ['mac', 'win', 'win-xp', 'win-vista', 'linux']
-ARCHIVE_DIR_NAME_DICT = {'win': 'Webkit_Win',
+ARCHIVE_DIR_NAME_DICT = {'win': 'Webkit_Win__deps_',
'win-vista': 'webkit-dbg-vista',
- 'win-xp': 'Webkit_Win',
- 'mac': 'Webkit_Mac10_5',
- 'linux': 'webkit-rel-linux64',
- 'win-canary': 'webkit-rel-webkit-org',
+ 'win-xp': 'Webkit_Win__deps_',
+ 'mac': 'Webkit_Mac10_5__deps_',
+ 'linux': 'Webkit_Linux__deps_',
+ 'win-canary': 'Webkit_Win',
'win-vista-canary': 'webkit-dbg-vista',
- 'win-xp-canary': 'webkit-rel-webkit-org',
- 'mac-canary': 'webkit-rel-mac-webkit-org',
- 'linux-canary': 'webkit-rel-linux-webkit-org'}
+ 'win-xp-canary': 'Webkit_Win',
+ 'mac-canary': 'Webkit_Mac10_5',
+ 'linux-canary': 'Webkit_Linux'}
def log_dashed_string(text, platform, logging_level=logging.INFO):
@@ -100,41 +92,35 @@ def log_dashed_string(text, platform, logging_level=logging.INFO):
_log.info(msg)
-def setup_html_directory(html_directory):
+def setup_html_directory(filesystem, parent_directory):
"""Setup the directory to store html results.
- All html related files are stored in the "rebaseline_html" subdirectory.
-
- Args:
- html_directory: parent directory that stores the rebaselining results.
- If None, a temp directory is created.
-
- Returns:
- the directory that stores the html related rebaselining results.
+ All html related files are stored in the "rebaseline_html" subdirectory of
+ the parent directory. The path to the created directory is returned.
"""
- if not html_directory:
- html_directory = tempfile.mkdtemp()
- elif not os.path.exists(html_directory):
- os.mkdir(html_directory)
+ if not parent_directory:
+ parent_directory = str(filesystem.mkdtemp())
+ else:
+ filesystem.maybe_make_directory(parent_directory)
- html_directory = os.path.join(html_directory, 'rebaseline_html')
+ html_directory = filesystem.join(parent_directory, 'rebaseline_html')
_log.info('Html directory: "%s"', html_directory)
- if os.path.exists(html_directory):
- shutil.rmtree(html_directory, True)
- _log.info('Deleted file at html directory: "%s"', html_directory)
+ if filesystem.exists(html_directory):
+ filesystem.rmtree(html_directory)
+ _log.info('Deleted html directory: "%s"', html_directory)
- if not os.path.exists(html_directory):
- os.mkdir(html_directory)
+ filesystem.maybe_make_directory(html_directory)
return html_directory
-def get_result_file_fullpath(html_directory, baseline_filename, platform,
+def get_result_file_fullpath(filesystem, html_directory, baseline_filename, platform,
result_type):
"""Get full path of the baseline result file.
Args:
+ filesystem: wrapper object
html_directory: directory that stores the html related files.
baseline_filename: name of the baseline file.
platform: win, linux or mac
@@ -144,9 +130,9 @@ def get_result_file_fullpath(html_directory, baseline_filename, platform,
Full path of the baseline file for rebaselining result comparison.
"""
- base, ext = os.path.splitext(baseline_filename)
+ base, ext = filesystem.splitext(baseline_filename)
result_filename = '%s-%s-%s%s' % (base, platform, result_type, ext)
- fullpath = os.path.join(html_directory, result_filename)
+ fullpath = filesystem.join(html_directory, result_filename)
_log.debug(' Result file full path: "%s".', fullpath)
return fullpath
@@ -168,6 +154,7 @@ class Rebaseliner(object):
self._platform = platform
self._options = options
self._port = running_port
+ self._filesystem = running_port._filesystem
self._target_port = target_port
self._rebaseline_port = port.get(
self._target_port.test_platform_name_to_name(platform), options)
@@ -370,7 +357,7 @@ class Rebaseliner(object):
found = False
scm_error = False
- test_basename = os.path.splitext(test)[0]
+ test_basename = self._filesystem.splitext(test)[0]
for suffix in BASELINE_SUFFIXES:
archive_test_name = ('layout-test-results/%s-actual%s' %
(test_basename, suffix))
@@ -385,15 +372,14 @@ class Rebaseliner(object):
# Extract new baseline from archive and save it to a temp file.
data = zip_file.read(archive_test_name)
- temp_fd, temp_name = tempfile.mkstemp(suffix)
- f = os.fdopen(temp_fd, 'wb')
- f.write(data)
- f.close()
+ tempfile, temp_name = self._filesystem.open_binary_tempfile(suffix)
+ tempfile.write(data)
+ tempfile.close()
expected_filename = '%s-expected%s' % (test_basename, suffix)
- expected_fullpath = os.path.join(
+ expected_fullpath = self._filesystem.join(
self._rebaseline_port.baseline_path(), expected_filename)
- expected_fullpath = os.path.normpath(expected_fullpath)
+ expected_fullpath = self._filesystem.normpath(expected_fullpath)
_log.debug(' Expected file full path: "%s"',
expected_fullpath)
@@ -407,16 +393,13 @@ class Rebaseliner(object):
test,
suffix,
self._platform):
- os.remove(temp_name)
+ self._filesystem.remove(temp_name)
self._delete_baseline(expected_fullpath)
continue
- # Create the new baseline directory if it doesn't already
- # exist.
- self._port.maybe_make_directory(
- os.path.dirname(expected_fullpath))
+ self._filesystem.maybe_make_directory(self._filesystem.dirname(expected_fullpath))
- shutil.move(temp_name, expected_fullpath)
+ self._filesystem.move(temp_name, expected_fullpath)
if 0 != self._scm.add(expected_fullpath, return_exit_code=True):
# FIXME: print detailed diagnose messages
@@ -436,7 +419,7 @@ class Rebaseliner(object):
test_no += 1
zip_file.close()
- os.remove(archive_file)
+ self._filesystem.remove(archive_file)
return self._rebaselined_tests
@@ -458,21 +441,17 @@ class Rebaseliner(object):
True if the baseline is unnecessary.
False otherwise.
"""
- test_filepath = os.path.join(self._target_port.layout_tests_dir(),
+ test_filepath = self._filesystem.join(self._target_port.layout_tests_dir(),
test)
all_baselines = self._rebaseline_port.expected_baselines(
test_filepath, suffix, True)
for (fallback_dir, fallback_file) in all_baselines:
if fallback_dir and fallback_file:
- fallback_fullpath = os.path.normpath(
- os.path.join(fallback_dir, fallback_file))
+ fallback_fullpath = self._filesystem.normpath(
+ self._filesystem.join(fallback_dir, fallback_file))
if fallback_fullpath.lower() != baseline_path.lower():
- with codecs.open(new_baseline, "r",
- None) as file_handle1:
- new_output = file_handle1.read()
- with codecs.open(fallback_fullpath, "r",
- None) as file_handle2:
- fallback_output = file_handle2.read()
+ new_output = self._filesystem.read_binary_file(new_baseline)
+ fallback_output = self._filesystem.read_binary_file(fallback_fullpath)
is_image = baseline_path.lower().endswith('.png')
if not self._diff_baselines(new_output, fallback_output,
is_image):
@@ -507,7 +486,7 @@ class Rebaseliner(object):
filename: full path of the file to delete.
"""
- if not filename or not os.path.isfile(filename):
+ if not filename or not self._filesystem.isfile(filename):
return
self._scm.delete(filename)
@@ -530,14 +509,12 @@ class Rebaseliner(object):
date_suffix = time.strftime('%Y%m%d%H%M%S',
time.localtime(time.time()))
backup_file = ('%s.orig.%s' % (path, date_suffix))
- if os.path.exists(backup_file):
- os.remove(backup_file)
+ if self._filesystem.exists(backup_file):
+ self._filesystem.remove(backup_file)
_log.info('Saving original file to "%s"', backup_file)
- os.rename(path, backup_file)
- # FIXME: What encoding are these files?
- # Or is new_expectations always a byte array?
- with open(path, "w") as file:
- file.write(new_expectations)
+ self._filesystem.move(path, backup_file)
+
+ self._filesystem.write_text_file(path, new_expectations)
# self._scm.add(path)
else:
_log.info('No test was rebaselined so nothing to remove.')
@@ -551,15 +528,15 @@ class Rebaseliner(object):
baseline_fullpath: full path of the expected baseline file.
"""
- if not baseline_fullpath or not os.path.exists(baseline_fullpath):
+ if not baseline_fullpath or not self._filesystem.exists(baseline_fullpath):
return
# Copy the new baseline to html directory for result comparison.
- baseline_filename = os.path.basename(baseline_fullpath)
- new_file = get_result_file_fullpath(self._options.html_directory,
+ baseline_filename = self._filesystem.basename(baseline_fullpath)
+ new_file = get_result_file_fullpath(self._filesystem, self._options.html_directory,
baseline_filename, self._platform,
'new')
- shutil.copyfile(baseline_fullpath, new_file)
+ self._filesystem.copyfile(baseline_fullpath, new_file)
_log.info(' Html: copied new baseline file from "%s" to "%s".',
baseline_fullpath, new_file)
@@ -574,12 +551,13 @@ class Rebaseliner(object):
'NO SUCH FILE OR DIRECTORY')):
_log.info(' No base file: "%s"', baseline_fullpath)
return
- base_file = get_result_file_fullpath(self._options.html_directory,
+ base_file = get_result_file_fullpath(self._filesystem, self._options.html_directory,
baseline_filename, self._platform,
'old')
- # We should be using an explicit encoding here.
- with open(base_file, "wb") as file:
- file.write(output)
+ if base_file.upper().endswith('.PNG'):
+ self._filesystem.write_binary_file(base_file, output)
+ else:
+ self._filesystem.write_text_file(base_file, output)
_log.info(' Html: created old baseline file: "%s".',
base_file)
@@ -587,11 +565,10 @@ class Rebaseliner(object):
if baseline_filename.upper().endswith('.TXT'):
output = self._scm.diff_for_file(baseline_fullpath, log=_log)
if output:
- diff_file = get_result_file_fullpath(
+ diff_file = get_result_file_fullpath(self._filesystem,
self._options.html_directory, baseline_filename,
self._platform, 'diff')
- with open(diff_file, 'wb') as file:
- file.write(output)
+ self._filesystem.write_text_file(diff_file, output)
_log.info(' Html: created baseline diff file: "%s".',
diff_file)
@@ -642,19 +619,19 @@ class HtmlGenerator(object):
'<img style="width: 200" src="%(uri)s" /></a></td>')
HTML_TR = '<tr>%s</tr>'
- def __init__(self, target_port, options, platforms, rebaselining_tests,
- executive):
+ def __init__(self, port, target_port, options, platforms, rebaselining_tests):
self._html_directory = options.html_directory
+ self._port = port
self._target_port = target_port
self._platforms = platforms
self._rebaselining_tests = rebaselining_tests
- self._executive = executive
- self._html_file = os.path.join(options.html_directory,
- 'rebaseline.html')
+ self._filesystem = port._filesystem
+ self._html_file = self._filesystem.join(options.html_directory,
+ 'rebaseline.html')
def abspath_to_uri(self, filename):
"""Converts an absolute path to a file: URI."""
- return path.abspath_to_uri(filename, self._executive)
+ return path.abspath_to_uri(filename, self._port._executive)
def generate_html(self):
"""Generate html file for rebaselining result comparison."""
@@ -677,9 +654,7 @@ class HtmlGenerator(object):
'body': html_body})
_log.debug(html)
- with codecs.open(self._html_file, "w", "utf-8") as file:
- file.write(html)
-
+ self._filesystem.write_text_file(self._html_file, html)
_log.info('Baseline comparison html generated at "%s"',
self._html_file)
@@ -687,7 +662,7 @@ class HtmlGenerator(object):
"""Launch the rebaselining html in brwoser."""
_log.info('Launching html: "%s"', self._html_file)
- user.User().open_url(self._html_file)
+ self._port._user.open_url(self._html_file)
_log.info('Html launched.')
def _generate_baseline_links(self, test_basename, suffix, platform):
@@ -705,14 +680,14 @@ class HtmlGenerator(object):
baseline_filename = '%s-expected%s' % (test_basename, suffix)
_log.debug(' baseline filename: "%s"', baseline_filename)
- new_file = get_result_file_fullpath(self._html_directory,
+ new_file = get_result_file_fullpath(self._filesystem, self._html_directory,
baseline_filename, platform, 'new')
_log.info(' New baseline file: "%s"', new_file)
- if not os.path.exists(new_file):
+ if not self._filesystem.exists(new_file):
_log.info(' No new baseline file: "%s"', new_file)
return ''
- old_file = get_result_file_fullpath(self._html_directory,
+ old_file = get_result_file_fullpath(self._filesystem, self._html_directory,
baseline_filename, platform, 'old')
_log.info(' Old baseline file: "%s"', old_file)
if suffix == '.png':
@@ -721,7 +696,7 @@ class HtmlGenerator(object):
html_td_link = self.HTML_TD_LINK
links = ''
- if os.path.exists(old_file):
+ if self._filesystem.exists(old_file):
links += html_td_link % {
'uri': self.abspath_to_uri(old_file),
'name': baseline_filename}
@@ -732,11 +707,11 @@ class HtmlGenerator(object):
links += html_td_link % {'uri': self.abspath_to_uri(new_file),
'name': baseline_filename}
- diff_file = get_result_file_fullpath(self._html_directory,
+ diff_file = get_result_file_fullpath(self._filesystem, self._html_directory,
baseline_filename, platform,
'diff')
_log.info(' Baseline diff file: "%s"', diff_file)
- if os.path.exists(diff_file):
+ if self._filesystem.exists(diff_file):
links += html_td_link % {'uri': self.abspath_to_uri(diff_file),
'name': 'Diff'}
else:
@@ -755,7 +730,7 @@ class HtmlGenerator(object):
html that compares baseline results for the test.
"""
- test_basename = os.path.basename(os.path.splitext(test)[0])
+ test_basename = self._filesystem.basename(self._filesystem.splitext(test)[0])
_log.info(' basename: "%s"', test_basename)
rows = []
for suffix in BASELINE_SUFFIXES:
@@ -776,8 +751,7 @@ class HtmlGenerator(object):
rows.append(self.HTML_TR % row)
if rows:
- test_path = os.path.join(self._target_port.layout_tests_dir(),
- test)
+ test_path = self._filesystem.join(self._target_port.layout_tests_dir(), test)
html = self.HTML_TR_TEST % (self.abspath_to_uri(test_path), test)
html += self.HTML_TEST_DETAIL % ' '.join(rows)
@@ -883,7 +857,7 @@ def parse_options(args):
return (options, target_options)
-def main(executive=Executive()):
+def main():
"""Main function to produce new baselines."""
(options, target_options) = parse_options(sys.argv[1:])
@@ -929,7 +903,7 @@ def main(executive=Executive()):
if platform in platforms:
rebaseline_platforms.append(platform)
- options.html_directory = setup_html_directory(options.html_directory)
+ options.html_directory = setup_html_directory(host_port_obj._filesystem, options.html_directory)
rebaselining_tests = set()
backup = options.backup
@@ -950,11 +924,11 @@ def main(executive=Executive()):
_log.info('')
log_dashed_string('Rebaselining result comparison started', None)
- html_generator = HtmlGenerator(target_port_obj,
+ html_generator = HtmlGenerator(host_port_obj,
+ target_port_obj,
options,
rebaseline_platforms,
- rebaselining_tests,
- executive=executive)
+ rebaselining_tests)
html_generator.generate_html()
if not options.quiet:
html_generator.show_html()
diff --git a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py
index 7c55b94..50c0204 100644
--- a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py
@@ -29,15 +29,15 @@
"""Unit tests for rebaseline_chromium_webkit_tests.py."""
-import os
-import sys
import unittest
from webkitpy.tool import mocktool
-from webkitpy.layout_tests import port
-from webkitpy.layout_tests import rebaseline_chromium_webkit_tests
+from webkitpy.common.system import filesystem_mock
from webkitpy.common.system.executive import Executive, ScriptError
+import port
+import rebaseline_chromium_webkit_tests
+
class MockPort(object):
def __init__(self, image_diff_exists):
@@ -88,9 +88,10 @@ class TestRebaseliner(unittest.TestCase):
def make_rebaseliner(self):
options = mocktool.MockOptions(configuration=None,
html_directory=None)
- host_port_obj = port.get('test', options)
+ filesystem = filesystem_mock.MockFileSystem()
+ host_port_obj = port.get('test', options, filesystem=filesystem)
target_options = options
- target_port_obj = port.get('test', target_options)
+ target_port_obj = port.get('test', target_options, filesystem=filesystem)
platform = 'test'
return rebaseline_chromium_webkit_tests.Rebaseliner(
host_port_obj, target_port_obj, platform, options)
@@ -113,44 +114,43 @@ class TestRebaseliner(unittest.TestCase):
def test_diff_baselines_txt(self):
rebaseliner = self.make_rebaseliner()
output = rebaseliner._port.expected_text(
- os.path.join(rebaseliner._port.layout_tests_dir(),
- 'passes/text.html'))
+ rebaseliner._port._filesystem.join(rebaseliner._port.layout_tests_dir(),
+ 'passes/text.html'))
self.assertFalse(rebaseliner._diff_baselines(output, output,
is_image=False))
def test_diff_baselines_png(self):
rebaseliner = self.make_rebaseliner()
image = rebaseliner._port.expected_image(
- os.path.join(rebaseliner._port.layout_tests_dir(),
- 'passes/image.html'))
+ rebaseliner._port._filesystem.join(rebaseliner._port.layout_tests_dir(),
+ 'passes/image.html'))
self.assertFalse(rebaseliner._diff_baselines(image, image,
is_image=True))
class TestHtmlGenerator(unittest.TestCase):
- def make_generator(self, tests):
- return rebaseline_chromium_webkit_tests.HtmlGenerator(
+ def make_generator(self, files, tests):
+ options = mocktool.MockOptions(configuration=None, html_directory='/tmp')
+ host_port = port.get('test', options, filesystem=filesystem_mock.MockFileSystem(files))
+ generator = rebaseline_chromium_webkit_tests.HtmlGenerator(
+ host_port,
target_port=None,
- options=mocktool.MockOptions(configuration=None,
- html_directory='/tmp'),
+ options=options,
platforms=['mac'],
- rebaselining_tests=tests,
- executive=Executive())
+ rebaselining_tests=tests)
+ return generator, host_port
def test_generate_baseline_links(self):
- orig_platform = sys.platform
- orig_exists = os.path.exists
-
- try:
- sys.platform = 'darwin'
- os.path.exists = lambda x: True
- generator = self.make_generator(["foo.txt"])
- links = generator._generate_baseline_links("foo", ".txt", "mac")
- expected_links = '<td align=center><a href="file:///tmp/foo-expected-mac-old.txt">foo-expected.txt</a></td><td align=center><a href="file:///tmp/foo-expected-mac-new.txt">foo-expected.txt</a></td><td align=center><a href="file:///tmp/foo-expected-mac-diff.txt">Diff</a></td>'
- self.assertEqual(links, expected_links)
- finally:
- sys.platform = orig_platform
- os.path.exists = orig_exists
+ files = {
+ "/tmp/foo-expected-mac-old.txt": "",
+ "/tmp/foo-expected-mac-new.txt": "",
+ "/tmp/foo-expected-mac-diff.txt": "",
+ }
+ tests = ["foo.txt"]
+ generator, host_port = self.make_generator(files, tests)
+ links = generator._generate_baseline_links("foo", ".txt", "mac")
+ expected_links = '<td align=center><a href="file:///tmp/foo-expected-mac-old.txt">foo-expected.txt</a></td><td align=center><a href="file:///tmp/foo-expected-mac-new.txt">foo-expected.txt</a></td><td align=center><a href="file:///tmp/foo-expected-mac-diff.txt">Diff</a></td>'
+ self.assertEqual(links, expected_links)
if __name__ == '__main__':
diff --git a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
index a141661..17b6e89 100755
--- a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
+++ b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
@@ -32,7 +32,6 @@
from __future__ import with_statement
-import codecs
import errno
import logging
import optparse
@@ -80,7 +79,7 @@ def run(port, options, args, regular_output=sys.stderr,
printer.cleanup()
return 0
- last_unexpected_results = _gather_unexpected_results(options)
+ last_unexpected_results = _gather_unexpected_results(port._filesystem, options)
if options.print_last_failures:
printer.write("\n".join(last_unexpected_results) + "\n")
printer.cleanup()
@@ -146,7 +145,7 @@ def _set_up_derived_options(port_obj, options):
if not options.use_apache:
options.use_apache = sys.platform in ('darwin', 'linux2')
- if not os.path.isabs(options.results_directory):
+ if not port_obj._filesystem.isabs(options.results_directory):
# This normalizes the path to the build dir.
# FIXME: how this happens is not at all obvious; this is a dumb
# interface and should be cleaned up.
@@ -162,15 +161,16 @@ def _set_up_derived_options(port_obj, options):
return warnings
-def _gather_unexpected_results(options):
+def _gather_unexpected_results(filesystem, options):
"""Returns the unexpected results from the previous run, if any."""
last_unexpected_results = []
if options.print_last_failures or options.retest_last_failures:
- unexpected_results_filename = os.path.join(
- options.results_directory, "unexpected_results.json")
- with codecs.open(unexpected_results_filename, "r", "utf-8") as file:
- results = simplejson.load(file)
- last_unexpected_results = results['tests'].keys()
+ unexpected_results_filename = filesystem.join(
+ options.results_directory, "unexpected_results.json")
+ if filesystem.exists(unexpected_results_filename):
+ content = filesystem.read_text_file(unexpected_results_filename)
+ results = simplejson.loads(content)
+ last_unexpected_results = results['tests'].keys()
return last_unexpected_results
@@ -277,6 +277,8 @@ def parse_args(args=None):
default="layout-test-results",
help="Output results directory source dir, relative to Debug or "
"Release"),
+ optparse.make_option("--build-directory",
+ help="Path to the directory under which build files are kept (should not include configuration)"),
optparse.make_option("--new-baseline", action="store_true",
default=False, help="Save all generated results as new baselines "
"into the platform directory, overwriting whatever's "
diff --git a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
index 2bfac2f..677becd 100644
--- a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
@@ -30,14 +30,13 @@
"""Unit tests for run_webkit_tests."""
+from __future__ import with_statement
+
import codecs
import itertools
import logging
-import os
import Queue
-import shutil
import sys
-import tempfile
import thread
import time
import threading
@@ -45,6 +44,7 @@ import unittest
from webkitpy.common import array_stream
from webkitpy.common.system import outputcapture
+from webkitpy.common.system import filesystem_mock
from webkitpy.common.system import user
from webkitpy.layout_tests import port
from webkitpy.layout_tests import run_webkit_tests
@@ -88,25 +88,25 @@ def parse_args(extra_args=None, record_results=False, tests_included=False,
def passing_run(extra_args=None, port_obj=None, record_results=False,
- tests_included=False):
+ tests_included=False, filesystem=None):
options, parsed_args = parse_args(extra_args, record_results,
tests_included)
if not port_obj:
port_obj = port.get(port_name=options.platform, options=options,
- user=MockUser())
+ user=MockUser(), filesystem=filesystem)
res = run_webkit_tests.run(port_obj, options, parsed_args)
return res == 0
-def logging_run(extra_args=None, port_obj=None, tests_included=False):
+def logging_run(extra_args=None, port_obj=None, record_results=False, tests_included=False, filesystem=None):
options, parsed_args = parse_args(extra_args=extra_args,
- record_results=False,
+ record_results=record_results,
tests_included=tests_included,
print_nothing=False)
user = MockUser()
if not port_obj:
port_obj = port.get(port_name=options.platform, options=options,
- user=user)
+ user=user, filesystem=filesystem)
res, buildbot_output, regular_output = run_and_capture(port_obj, options,
parsed_args)
@@ -127,7 +127,7 @@ def run_and_capture(port_obj, options, parsed_args):
return (res, buildbot_output, regular_output)
-def get_tests_run(extra_args=None, tests_included=False, flatten_batches=False):
+def get_tests_run(extra_args=None, tests_included=False, flatten_batches=False, filesystem=None):
extra_args = extra_args or []
if not tests_included:
# Not including http tests since they get run out of order (that
@@ -163,7 +163,7 @@ def get_tests_run(extra_args=None, tests_included=False, flatten_batches=False):
def create_driver(self, worker_number):
return RecordingTestDriver(self, worker_number)
- recording_port = RecordingTestPort(options=options, user=user)
+ recording_port = RecordingTestPort(options=options, user=user, filesystem=filesystem)
run_and_capture(recording_port, options, parsed_args)
if flatten_batches:
@@ -239,9 +239,12 @@ class MainTest(unittest.TestCase):
['failures/expected/keyboard.html'], tests_included=True)
def test_last_results(self):
- passing_run(['--clobber-old-results'], record_results=True)
+ fs = port.unit_test_filesystem()
+ # We do a logging run here instead of a passing run in order to
+ # suppress the output from the json generator.
+ (res, buildbot_output, regular_output, user) = logging_run(['--clobber-old-results'], record_results=True, filesystem=fs)
(res, buildbot_output, regular_output, user) = logging_run(
- ['--print-last-failures'])
+ ['--print-last-failures'], filesystem=fs)
self.assertEqual(regular_output.get(), ['\n\n'])
self.assertEqual(buildbot_output.get(), [])
@@ -315,19 +318,33 @@ class MainTest(unittest.TestCase):
tests_run = get_tests_run(['passes/text.html'], tests_included=True, flatten_batches=True)
self.assertEquals(['passes/text.html'], tests_run)
+ def test_single_file_with_prefix(self):
+ tests_run = get_tests_run(['LayoutTests/passes/text.html'], tests_included=True, flatten_batches=True)
+ self.assertEquals(['passes/text.html'], tests_run)
+
+ def test_single_skipped_file(self):
+ tests_run = get_tests_run(['failures/expected/keybaord.html'], tests_included=True, flatten_batches=True)
+ self.assertEquals([], tests_run)
+
def test_test_list(self):
- filename = tempfile.mktemp()
- tmpfile = file(filename, mode='w+')
- tmpfile.write('passes/text.html')
- tmpfile.close()
- tests_run = get_tests_run(['--test-list=%s' % filename], tests_included=True, flatten_batches=True)
+ fs = port.unit_test_filesystem()
+ filename = '/tmp/foo.txt'
+ fs.write_text_file(filename, 'passes/text.html')
+ tests_run = get_tests_run(['--test-list=%s' % filename], tests_included=True, flatten_batches=True, filesystem=fs)
self.assertEquals(['passes/text.html'], tests_run)
- os.remove(filename)
+ fs.remove(filename)
res, out, err, user = logging_run(['--test-list=%s' % filename],
- tests_included=True)
+ tests_included=True, filesystem=fs)
self.assertEqual(res, -1)
self.assertFalse(err.empty())
+ def test_test_list_with_prefix(self):
+ fs = port.unit_test_filesystem()
+ filename = '/tmp/foo.txt'
+ fs.write_text_file(filename, 'LayoutTests/passes/text.html')
+ tests_run = get_tests_run(['--test-list=%s' % filename], tests_included=True, flatten_batches=True, filesystem=fs)
+ self.assertEquals(['passes/text.html'], tests_run)
+
def test_unexpected_failures(self):
# Run tests including the unexpected failures.
self._url_opened = None
@@ -393,11 +410,11 @@ class MainTest(unittest.TestCase):
# We run a configuration that should fail, to generate output, then
# look for what the output results url was.
- tmpdir = tempfile.mkdtemp()
- res, out, err, user = logging_run(['--results-directory=' + tmpdir],
- tests_included=True)
- self.assertEqual(user.url, os.path.join(tmpdir, 'results.html'))
- shutil.rmtree(tmpdir, ignore_errors=True)
+ fs = port.unit_test_filesystem()
+ with fs.mkdtemp() as tmpdir:
+ res, out, err, user = logging_run(['--results-directory=' + str(tmpdir)],
+ tests_included=True, filesystem=fs)
+ self.assertEqual(user.url, fs.join(tmpdir, 'results.html'))
def test_results_directory_default(self):
# We run a configuration that should fail, to generate output, then
@@ -454,18 +471,6 @@ class MainTest(unittest.TestCase):
MainTest = skip_if(MainTest, sys.platform == 'cygwin' and compare_version(sys, '2.6')[0] < 0, 'new-run-webkit-tests tests hang on Cygwin Python 2.5.2')
-
-def _mocked_open(original_open, file_list):
- def _wrapper(name, mode, encoding):
- if name.find("-expected.") != -1 and mode.find("w") != -1:
- # we don't want to actually write new baselines, so stub these out
- name.replace('\\', '/')
- file_list.append(name)
- return original_open(os.devnull, mode, encoding)
- return original_open(name, mode, encoding)
- return _wrapper
-
-
class RebaselineTest(unittest.TestCase):
def assertBaselines(self, file_list, file):
"assert that the file_list contains the baselines."""
@@ -476,49 +481,39 @@ class RebaselineTest(unittest.TestCase):
# FIXME: Add tests to ensure that we're *not* writing baselines when we're not
# supposed to be.
- def disabled_test_reset_results(self):
- # FIXME: This test is disabled until we can rewrite it to use a
- # mock filesystem.
- #
+ def test_reset_results(self):
# Test that we update expectations in place. If the expectation
# is missing, update the expected generic location.
- file_list = []
+ fs = port.unit_test_filesystem()
passing_run(['--pixel-tests',
'--reset-results',
'passes/image.html',
'failures/expected/missing_image.html'],
- tests_included=True)
+ tests_included=True, filesystem=fs)
+ file_list = fs.written_files.keys()
+ file_list.remove('/tmp/layout-test-results/tests_run.txt')
self.assertEqual(len(file_list), 6)
self.assertBaselines(file_list,
- "data/passes/image")
+ "/passes/image")
self.assertBaselines(file_list,
- "data/failures/expected/missing_image")
+ "/failures/expected/missing_image")
- def disabled_test_new_baseline(self):
- # FIXME: This test is disabled until we can rewrite it to use a
- # mock filesystem.
- #
+ def test_new_baseline(self):
# Test that we update the platform expectations. If the expectation
# is mssing, then create a new expectation in the platform dir.
- file_list = []
- original_open = codecs.open
- try:
- # Test that we update the platform expectations. If the expectation
- # is mssing, then create a new expectation in the platform dir.
- file_list = []
- codecs.open = _mocked_open(original_open, file_list)
- passing_run(['--pixel-tests',
- '--new-baseline',
- 'passes/image.html',
- 'failures/expected/missing_image.html'],
- tests_included=True)
- self.assertEqual(len(file_list), 6)
- self.assertBaselines(file_list,
- "data/platform/test/passes/image")
- self.assertBaselines(file_list,
- "data/platform/test/failures/expected/missing_image")
- finally:
- codecs.open = original_open
+ fs = port.unit_test_filesystem()
+ passing_run(['--pixel-tests',
+ '--new-baseline',
+ 'passes/image.html',
+ 'failures/expected/missing_image.html'],
+ tests_included=True, filesystem=fs)
+ file_list = fs.written_files.keys()
+ file_list.remove('/tmp/layout-test-results/tests_run.txt')
+ self.assertEqual(len(file_list), 6)
+ self.assertBaselines(file_list,
+ "/platform/test/passes/image")
+ self.assertBaselines(file_list,
+ "/platform/test/failures/expected/missing_image")
class DryrunTest(unittest.TestCase):
@@ -526,15 +521,14 @@ class DryrunTest(unittest.TestCase):
# chromium platforms require a chromium checkout, and the mac platform
# requires fcntl, so it can't be tested on win32, etc. There is
# probably a better way of handling this.
- def test_darwin(self):
+ def disabled_test_darwin(self):
if sys.platform != "darwin":
return
- self.assertTrue(passing_run(['--platform', 'test']))
- self.assertTrue(passing_run(['--platform', 'dryrun',
- 'fast/html']))
- self.assertTrue(passing_run(['--platform', 'dryrun-mac',
- 'fast/html']))
+ self.assertTrue(passing_run(['--platform', 'dryrun', 'fast/html'],
+ tests_included=True))
+ self.assertTrue(passing_run(['--platform', 'dryrun-mac', 'fast/html'],
+ tests_included=True))
def test_test(self):
self.assertTrue(passing_run(['--platform', 'dryrun-test',
diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py b/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py
index da466c8..44605d2 100644
--- a/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py
+++ b/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py
@@ -34,13 +34,8 @@ match, returns FailureImageHashMismatch and outputs both hashes into the layout
test results directory.
"""
-from __future__ import with_statement
-
-import codecs
import errno
import logging
-import os
-import shutil
from webkitpy.layout_tests.layout_package import test_failures
from webkitpy.layout_tests.test_types import test_type_base
diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py b/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py
index 4b96b3a..ad65016 100644
--- a/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py
+++ b/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py
@@ -32,13 +32,9 @@
Also defines the TestArguments "struct" to pass them additional arguments.
"""
-from __future__ import with_statement
-
-import codecs
import cgi
import errno
import logging
-import os.path
_log = logging.getLogger("webkitpy.layout_tests.test_types.test_type_base")
@@ -86,9 +82,10 @@ class TestTypeBase(object):
def _make_output_directory(self, filename):
"""Creates the output directory (if needed) for a given test
filename."""
- output_filename = os.path.join(self._root_output_dir,
+ fs = self._port._filesystem
+ output_filename = fs.join(self._root_output_dir,
self._port.relative_test_filename(filename))
- self._port.maybe_make_directory(os.path.split(output_filename)[0])
+ fs.maybe_make_directory(fs.dirname(output_filename))
def _save_baseline_data(self, filename, data, modifier, encoding,
generate_new_baseline=True):
@@ -106,21 +103,22 @@ class TestTypeBase(object):
baseline, or update the existing one
"""
+ port = self._port
+ fs = self._port._filesystem
if generate_new_baseline:
- relative_dir = os.path.dirname(
- self._port.relative_test_filename(filename))
- baseline_path = self._port.baseline_path()
- output_dir = os.path.join(baseline_path, relative_dir)
- output_file = os.path.basename(os.path.splitext(filename)[0] +
+ relative_dir = fs.dirname(port.relative_test_filename(filename))
+ baseline_path = port.baseline_path()
+ output_dir = fs.join(baseline_path, relative_dir)
+ output_file = fs.basename(fs.splitext(filename)[0] +
self.FILENAME_SUFFIX_EXPECTED + modifier)
- self._port.maybe_make_directory(output_dir)
- output_path = os.path.join(output_dir, output_file)
+ fs.maybe_make_directory(output_dir)
+ output_path = fs.join(output_dir, output_file)
_log.debug('writing new baseline result "%s"' % (output_path))
else:
- output_path = self._port.expected_filename(filename, modifier)
+ output_path = port.expected_filename(filename, modifier)
_log.debug('resetting baseline result "%s"' % output_path)
- self._port.update_baseline(output_path, data, encoding)
+ port.update_baseline(output_path, data, encoding)
def output_filename(self, filename, modifier):
"""Returns a filename inside the output dir that contains modifier.
@@ -136,9 +134,10 @@ class TestTypeBase(object):
Return:
The absolute windows path to the output filename
"""
- output_filename = os.path.join(self._root_output_dir,
+ fs = self._port._filesystem
+ output_filename = fs.join(self._root_output_dir,
self._port.relative_test_filename(filename))
- return os.path.splitext(output_filename)[0] + modifier
+ return fs.splitext(output_filename)[0] + modifier
def compare_output(self, port, filename, test_args, actual_test_output,
expected_test_output):
@@ -165,11 +164,11 @@ class TestTypeBase(object):
def _write_into_file_at_path(self, file_path, contents, encoding):
"""This method assumes that byte_array is already encoded
into the right format."""
- open_mode = 'w'
+ fs = self._port._filesystem
if encoding is None:
- open_mode = 'w+b'
- with codecs.open(file_path, open_mode, encoding=encoding) as file:
- file.write(contents)
+ fs.write_binary_file(file_path, contents)
+ return
+ fs.write_text_file(file_path, contents)
def write_output_files(self, filename, file_type,
output, expected, encoding,
diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py b/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py
index ad25262..7b7febe 100644
--- a/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py
+++ b/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py
@@ -33,12 +33,8 @@ If the output doesn't match, returns FailureTextMismatch and outputs the diff
files into the layout test results directory.
"""
-from __future__ import with_statement
-
-import codecs
import errno
import logging
-import os.path
from webkitpy.layout_tests.layout_package import test_failures
from webkitpy.layout_tests.test_types import test_type_base
diff --git a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py
index 3be2556..b22138d 100644
--- a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py
+++ b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py
@@ -187,7 +187,9 @@ class CommitQueueTask(object):
first_failing_tests = [result.filename for result in first_results]
first_results_archive = self._delegate.archive_last_layout_test_results(self._patch)
if self._test():
- self._report_flaky_tests(first_results, first_results_archive)
+ # Only report flaky tests if we were successful at archiving results.
+ if first_results_archive:
+ self._report_flaky_tests(first_results, first_results_archive)
return True
second_results = self._failing_results_from_last_run()
diff --git a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py
index 26231ae..87d0ab5 100644
--- a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py
+++ b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py
@@ -209,6 +209,34 @@ command_passed: success_message='Landed patch' patch='197'
"""
self._run_through_task(commit_queue, expected_stderr)
+ def test_failed_archive(self):
+ commit_queue = MockCommitQueue([
+ None,
+ None,
+ None,
+ None,
+ ScriptError("MOCK tests failure"),
+ ])
+ # It's possible delegate to fail to archive layout tests, don't try to report
+ # flaky tests when that happens.
+ commit_queue.archive_last_layout_test_results = lambda patch: None
+ expected_stderr = """run_webkit_patch: ['clean']
+command_passed: success_message='Cleaned working directory' patch='197'
+run_webkit_patch: ['update']
+command_passed: success_message='Updated working directory' patch='197'
+run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 197]
+command_passed: success_message='Applied patch' patch='197'
+run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=both']
+command_passed: success_message='Built patch' patch='197'
+run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
+command_failed: failure_message='Patch does not pass tests' script_error='MOCK tests failure' patch='197'
+run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
+command_passed: success_message='Passed tests' patch='197'
+run_webkit_patch: ['land-attachment', '--force-clean', '--ignore-builders', '--non-interactive', '--parent-command=commit-queue', 197]
+command_passed: success_message='Landed patch' patch='197'
+"""
+ self._run_through_task(commit_queue, expected_stderr)
+
_double_flaky_test_counter = 0
def test_double_flaky_test_failure(self):
diff --git a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py
index 3b53d1a..996ab24 100644
--- a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py
+++ b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py
@@ -122,6 +122,7 @@ class EflEWS(AbstractEarlyWarningSystem):
"leandro@profusion.mobi",
"antognolli@profusion.mobi",
"lucas.demarchi@profusion.mobi",
+ "gyuyoung.kim@samsung.com",
]
diff --git a/Tools/Scripts/webkitpy/tool/commands/queues.py b/Tools/Scripts/webkitpy/tool/commands/queues.py
index 42321cf..9e50dd4 100644
--- a/Tools/Scripts/webkitpy/tool/commands/queues.py
+++ b/Tools/Scripts/webkitpy/tool/commands/queues.py
@@ -323,10 +323,12 @@ class CommitQueue(AbstractPatchQueue, StepSequenceErrorHandler, CommitQueueTaskD
results_name, _ = os.path.splitext(os.path.basename(results_directory))
# Note: We name the zip with the bug_id instead of patch_id to match work_item_log_path().
zip_path = self._tool.workspace.find_unused_filename(self._log_directory(), "%s-%s" % (patch.bug_id(), results_name), "zip")
+ if not zip_path:
+ return None
archive = self._tool.workspace.create_zip(zip_path, results_directory)
# Remove the results directory to prevent http logs, etc. from getting huge between runs.
# We could have create_zip remove the original, but this is more explicit.
- self._tool.filesystem.remove_tree(results_directory, ignore_errors=True)
+ self._tool.filesystem.rmtree(results_directory)
return archive
def refetch_patch(self, patch):
diff --git a/Tools/Scripts/webkitpy/tool/main.py b/Tools/Scripts/webkitpy/tool/main.py
index 76d5bef..6b07615 100755
--- a/Tools/Scripts/webkitpy/tool/main.py
+++ b/Tools/Scripts/webkitpy/tool/main.py
@@ -36,6 +36,7 @@ import threading
from webkitpy.common.checkout.api import Checkout
from webkitpy.common.checkout.scm import default_scm
from webkitpy.common.config.ports import WebKitPort
+from webkitpy.common.host import Host
from webkitpy.common.net.bugzilla import Bugzilla
from webkitpy.common.net.buildbot import BuildBot
from webkitpy.common.net.irc.ircproxy import IRCProxy
@@ -46,7 +47,7 @@ from webkitpy.tool.multicommandtool import MultiCommandTool
import webkitpy.tool.commands as commands
-class WebKitPatch(MultiCommandTool):
+class WebKitPatch(MultiCommandTool, Host):
global_options = [
make_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="enable all logging"),
make_option("-d", "--directory", action="append", dest="patch_directories", default=[], help="Directory to look at for changed files"),
@@ -59,58 +60,14 @@ class WebKitPatch(MultiCommandTool):
def __init__(self, path):
MultiCommandTool.__init__(self)
+ Host.__init__(self)
self._path = path
self.wakeup_event = threading.Event()
- # FIXME: All of these shared objects should move off onto a
- # separate "Tool" object. WebKitPatch should inherit from
- # "Tool" and all these objects should use getters/setters instead of
- # manual getter functions (e.g. scm()).
- self.bugs = Bugzilla()
- self.buildbot = BuildBot()
- self.executive = executive.Executive()
- self._irc = None
- self.filesystem = filesystem.FileSystem()
- self.workspace = workspace.Workspace(self.filesystem, self.executive)
- self._port = None
- self.user = user.User()
- self._scm = None
- self._checkout = None
- self.status_server = StatusServer()
- self.port_factory = port.factory
- self.platform = platforminfo.PlatformInfo()
-
- def scm(self):
- # Lazily initialize SCM to not error-out before command line parsing (or when running non-scm commands).
- if not self._scm:
- self._scm = default_scm(self._options.patch_directories)
- return self._scm
-
- def checkout(self):
- if not self._checkout:
- self._checkout = Checkout(self.scm())
- return self._checkout
-
- def port(self):
- return self._port
-
- def ensure_irc_connected(self, irc_delegate):
- if not self._irc:
- self._irc = IRCProxy(irc_delegate)
-
- def irc(self):
- # We don't automatically construct IRCProxy here because constructing
- # IRCProxy actually connects to IRC. We want clients to explicitly
- # connect to IRC.
- return self._irc
def path(self):
return self._path
- def command_completed(self):
- if self._irc:
- self._irc.disconnect()
-
def should_show_in_main_help(self, command):
if not command.show_in_main_help:
return False
@@ -120,7 +77,7 @@ class WebKitPatch(MultiCommandTool):
# FIXME: This may be unnecessary since we pass global options to all commands during execute() as well.
def handle_global_options(self, options):
- self._options = options
+ self._initialize_scm(options.patch_directories)
if options.dry_run:
self.scm().dryrun = True
self.bugs.dryrun = True