[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc
dpranke at chromium.org
dpranke at chromium.org
Wed Dec 22 15:35:43 UTC 2010
The following commit has been merged in the debian/experimental branch:
commit 6a1f95919b1e6e46fd6516a28fed6044c2f07075
Author: dpranke at chromium.org <dpranke at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Mon Nov 8 23:36:07 2010 +0000
2010-11-08 Dirk Pranke <dpranke at chromium.org>
Reviewed by Eric Seidel.
Fix the webkit_base_dir logic in webkitpy/layout_tests/port/config.py.
It turns out that NRWT can't use the code in scm.find_checkout_root()
because the Chromium bots don't do full checkouts of the WebKit
tree; they only check out subdirectories like WebKitTools/Scripts.
Until we can figure out a better approach for this, I've
restored the base_dir-detecting code from NRWT, which works in
any directory tree, scm or no.
This also restores the files modified in r71475 and r71474.
https://bugs.webkit.org/show_bug.cgi?id=49151
* WebKitTools/Scripts/webkitpy/layout_tests/port/config.py
* WebKitTools/Scripts/webkitpy/layout_tests/port/config_unittest.py
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@71580 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog
index 1a18426..589edc9 100644
--- a/WebKitTools/ChangeLog
+++ b/WebKitTools/ChangeLog
@@ -1,3 +1,22 @@
+2010-11-08 Dirk Pranke <dpranke at chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix the webkit_base_dir logic in webkitpy/layout_tests/port/config.py.
+ It turns out that NRWT can't use the code in scm.find_checkout_root()
+ because the Chromium bots don't do full checkouts of the WebKit
+ tree; they only check out subdirectories like WebKitTools/Scripts.
+ Until we can figure out a better approach for this, I've
+ restored the base_dir-detecting code from NRWT, which works in
+ any directory tree, scm or no.
+
+ This also restores the files modified in r71475 and r71474.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49151
+
+ * WebKitTools/Scripts/webkitpy/layout_tests/port/config.py
+ * WebKitTools/Scripts/webkitpy/layout_tests/port/config_unittest.py
+
2010-11-08 Eric Seidel <eric at webkit.org>
Reviewed by Adam Barth.
@@ -201,7 +220,7 @@
Unreviewed, rolling out r71475.
http://trac.webkit.org/changeset/71475
-
+
breaks chromium webkit tests
https://bugs.webkit.org/show_bug.cgi?id=49151
diff --git a/WebKitTools/Scripts/webkitpy/common/newstringio.py b/WebKitTools/Scripts/webkitpy/common/newstringio.py
new file mode 100644
index 0000000..f6d08ec
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/common/newstringio.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""'with'-compliant StringIO implementation."""
+
+import StringIO
+
+
+class StringIO(StringIO.StringIO):
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, traceback):
+ pass
diff --git a/WebKitTools/Scripts/webkitpy/common/newstringio_unittest.py b/WebKitTools/Scripts/webkitpy/common/newstringio_unittest.py
new file mode 100644
index 0000000..5755c98
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/common/newstringio_unittest.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit tests for newstringio module."""
+
+from __future__ import with_statement
+
+import unittest
+
+import newstringio
+
+
+class NewStringIOTest(unittest.TestCase):
+ def test_with(self):
+ with newstringio.StringIO("foo") as f:
+ contents = f.read()
+ self.assertEqual(contents, "foo")
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/WebKitTools/Scripts/webkitpy/common/system/executive_mock.py b/WebKitTools/Scripts/webkitpy/common/system/executive_mock.py
new file mode 100644
index 0000000..7347ff9
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/common/system/executive_mock.py
@@ -0,0 +1,55 @@
+# Copyright (C) 2009 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# FIXME: Implement the rest of the interface as needed for testing :).
+
+# FIXME: Unify with tool/mocktool.MockExecutive.
+
+
+class MockExecutive2(object):
+ def __init__(self, output='', exit_code=0, exception=None):
+ self._output = output
+ self._exit_code = exit_code
+ self._exception = exception
+
+ def cpu_count(self):
+ return 2
+
+ def kill_all(self, process_name):
+ pass
+
+ def kill_process(self, pid):
+ pass
+
+ def run_command(self, arg_list, return_exit_code=False,
+ decode_output=False):
+ if self._exception:
+ raise self._exception
+ if return_exit_code:
+ return self._exit_code
+ return self._output
diff --git a/WebKitTools/Scripts/webkitpy/common/system/filesystem_mock.py b/WebKitTools/Scripts/webkitpy/common/system/filesystem_mock.py
new file mode 100644
index 0000000..d2cde4f
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/common/system/filesystem_mock.py
@@ -0,0 +1,75 @@
+# Copyright (C) 2009 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import errno
+import os
+import path
+
+
+class MockFileSystem(object):
+ def __init__(self, files={}):
+ """Initializes a "mock" filesystem that can be used to completely
+ stub out a filesystem.
+
+ Args:
+ files: a dict of filenames -> file contents. A file contents
+ value of None is used to indicate that the file should
+ not exist (even if standalone is False).
+ standalone: If True, only the files listed in _files_ exist.
+ If False, the object will pass through read calls to the
+ underlying filesystem. Writes are never passed through.
+
+ """
+ self.files = files
+
+ def exists(self, path):
+ if path in self.files:
+ return self.files[path] is not None
+ return False
+
+ def join(self, *comps):
+ return '/'.join(comps)
+
+ def maybe_make_directory(self, *path):
+ # FIXME: Implement such that subsequent calls to isdir() work?
+ pass
+
+ 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]
+
+ 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
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py
index a98b858..4a2970e 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py
@@ -30,10 +30,7 @@
"""Abstract base class of Port-specific entrypoints for the layout tests
test infrastructure (the Port and Driver classes)."""
-from __future__ import with_statement
-
import cgi
-import codecs
import difflib
import errno
import os
@@ -42,15 +39,17 @@ import sys
import time
import apache_http_server
+import config as port_config
import http_lock
import http_server
import test_files
import websocket_server
-from webkitpy.common.memoized import memoized
+from webkitpy.common import system
+from webkitpy.common.system import filesystem
from webkitpy.common.system import logutils
+from webkitpy.common.system import path
from webkitpy.common.system.executive import Executive, ScriptError
-from webkitpy.common.system.path import abspath_to_uri
from webkitpy.common.system.user import User
@@ -75,27 +74,26 @@ class DummyOptions(object):
# FIXME: This class should merge with webkitpy.webkit_port at some point.
class Port(object):
- """Abstract class for Port-specific hooks for the layout_test package.
- """
-
- @staticmethod
- def flag_from_configuration(configuration):
- flags_by_configuration = {
- "Debug": "--debug",
- "Release": "--release",
- }
- return flags_by_configuration[configuration]
-
- def __init__(self, **kwargs):
- self._name = kwargs.get('port_name', None)
- self._options = kwargs.get('options')
+ """Abstract class for Port-specific hooks for the layout_test package."""
+
+ def __init__(self, port_name=None, options=None,
+ executive=None,
+ user=None,
+ filesystem=None,
+ config=None,
+ **kwargs):
+ self._name = port_name
+ self._options = options
if self._options is None:
# FIXME: Ideally we'd have a package-wide way to get a
# well-formed options object that had all of the necessary
# options defined on it.
self._options = DummyOptions()
- self._executive = kwargs.get('executive', Executive())
- self._user = kwargs.get('user', User())
+ self._executive = executive or Executive()
+ self._user = user or User()
+ self._filesystem = filesystem or system.filesystem.FileSystem()
+ self._config = config or port_config.Config(self._executive,
+ self._filesystem)
self._helper = None
self._http_server = None
self._webkit_base_dir = None
@@ -118,7 +116,7 @@ class Port(object):
self._wdiff_available = True
self._pretty_patch_path = self.path_from_webkit_base("BugsSite",
- "PrettyPatch", "prettify.rb")
+ "PrettyPatch", "prettify.rb")
self._pretty_patch_available = True
self.set_option_default('configuration', None)
if self._options.configuration is None:
@@ -265,7 +263,8 @@ class Port(object):
baselines = []
for platform_dir in baseline_search_path:
- if os.path.exists(os.path.join(platform_dir, baseline_filename)):
+ if self.path_exists(self._filesystem.join(platform_dir,
+ baseline_filename)):
baselines.append((platform_dir, baseline_filename))
if not all_baselines and baselines:
@@ -274,7 +273,8 @@ class Port(object):
# If it wasn't found in a platform directory, return the expected
# result in the test directory, even if no such file actually exists.
platform_dir = self.layout_tests_dir()
- if os.path.exists(os.path.join(platform_dir, baseline_filename)):
+ if self.path_exists(self._filesystem.join(platform_dir,
+ baseline_filename)):
baselines.append((platform_dir, baseline_filename))
if baselines:
@@ -304,35 +304,32 @@ class Port(object):
platform_dir, baseline_filename = self.expected_baselines(
filename, suffix)[0]
if platform_dir:
- return os.path.join(platform_dir, baseline_filename)
- return os.path.join(self.layout_tests_dir(), baseline_filename)
-
- def _expected_file_contents(self, test, extension, encoding):
- path = self.expected_filename(test, extension)
- if not os.path.exists(path):
- return None
- open_mode = 'r'
- if encoding is None:
- open_mode = 'r+b'
- with codecs.open(path, open_mode, encoding) as file:
- return file.read()
+ return self._filesystem.join(platform_dir, baseline_filename)
+ return self._filesystem.join(self.layout_tests_dir(), baseline_filename)
def expected_checksum(self, test):
"""Returns the checksum of the image we expect the test to produce, or None if it is a text-only test."""
- return self._expected_file_contents(test, '.checksum', 'ascii')
+ path = self.expected_filename(test, '.checksum')
+ if not self.path_exists(path):
+ return None
+ return self._filesystem.read_text_file(path)
def expected_image(self, test):
"""Returns the image we expect the test to produce."""
- return self._expected_file_contents(test, '.png', None)
+ path = self.expected_filename(test, '.png')
+ if not self.path_exists(path):
+ return None
+ return self._filesystem.read_binary_file(path)
def expected_text(self, test):
"""Returns the text output we expect the test to produce."""
- # NOTE: -expected.txt files are ALWAYS utf-8. However,
- # we do not decode the output from DRT, so we should not
- # decode the -expected.txt values either to allow comparisons.
- text = self._expected_file_contents(test, '.txt', None)
- if not text:
+ # FIXME: DRT output is actually utf-8, but since we don't decode the
+ # output from DRT (instead treating it as a binary string), we read the
+ # baselines as a binary string, too.
+ path = self.expected_filename(test, '.txt')
+ if not self.path_exists(path):
return ''
+ text = self._filesystem.read_binary_file(path)
return text.strip("\r\n").replace("\r\n", "\n") + "\n"
def filename_to_uri(self, filename):
@@ -362,7 +359,7 @@ class Port(object):
protocol = "http"
return "%s://127.0.0.1:%u/%s" % (protocol, port, relative_path)
- return abspath_to_uri(os.path.abspath(filename))
+ return path.abspath_to_uri(os.path.abspath(filename))
def tests(self, paths):
"""Return the list of tests found (relative to layout_tests_dir()."""
@@ -373,20 +370,19 @@ class Port(object):
Used by --clobber-old-results."""
layout_tests_dir = self.layout_tests_dir()
- return filter(lambda x: os.path.isdir(os.path.join(layout_tests_dir, x)),
- os.listdir(layout_tests_dir))
+ return filter(lambda x: self._filesystem.isdir(self._filesystem.join(layout_tests_dir, x)),
+ self._filesystem.listdir(layout_tests_dir))
def path_isdir(self, path):
- """Returns whether the path refers to a directory of tests.
-
- Used by test_expectations.py to apply rules to whole directories."""
- return os.path.isdir(path)
+ """Return True if the path refers to a directory of tests."""
+ # Used by test_expectations.py to apply rules to whole directories.
+ return self._filesystem.isdir(path)
def path_exists(self, path):
- """Returns whether the path refers to an existing test or baseline."""
+ """Return True if the path refers to an existing test or baseline."""
# Used by test_expectations.py to determine if an entry refers to a
- # valid test and by printing.py to determine if baselines exist."""
- return os.path.exists(path)
+ # valid test and by printing.py to determine if baselines exist.
+ return self._filesystem.exists(path)
def update_baseline(self, path, data, encoding):
"""Updates the baseline for a test.
@@ -398,11 +394,12 @@ class Port(object):
data: contents of the baseline.
encoding: file encoding to use for the baseline.
"""
- write_mode = "w"
+ # FIXME: remove the encoding parameter in favor of text/binary
+ # functions.
if encoding is None:
- write_mode = "wb"
- with codecs.open(path, write_mode, encoding=encoding) as file:
- file.write(data)
+ self._filesystem.write_binary_file(path, data)
+ else:
+ self._filesystem.write_text_file(path, data)
def uri_to_test_name(self, uri):
"""Return the base layout test name for a given URI.
@@ -414,7 +411,7 @@ class Port(object):
"""
test = uri
if uri.startswith("file:///"):
- prefix = abspath_to_uri(self.layout_tests_dir()) + "/"
+ prefix = path.abspath_to_uri(self.layout_tests_dir()) + "/"
return test[len(prefix):]
if uri.startswith("http://127.0.0.1:8880/"):
@@ -441,18 +438,16 @@ class Port(object):
for test_or_category in self.skipped_layout_tests():
if test_or_category == test_name:
return True
- category = os.path.join(self.layout_tests_dir(), test_or_category)
- if os.path.isdir(category) and test_name.startswith(test_or_category):
+ category = self._filesystem.join(self.layout_tests_dir(),
+ test_or_category)
+ if (self._filesystem.isdir(category) and
+ test_name.startswith(test_or_category)):
return True
return False
def maybe_make_directory(self, *path):
"""Creates the specified directory if it doesn't already exist."""
- try:
- os.makedirs(os.path.join(*path))
- except OSError, e:
- if e.errno != errno.EEXIST:
- raise
+ self._filesystem.maybe_make_directory(*path)
def name(self):
"""Return the name of the port (e.g., 'mac', 'chromium-win-xp').
@@ -473,19 +468,13 @@ class Port(object):
if not hasattr(self._options, name):
return setattr(self._options, name, default_value)
- # FIXME: This could be replaced by functions in webkitpy.common.checkout.scm.
def path_from_webkit_base(self, *comps):
"""Returns the full path to path made by joining the top of the
WebKit source tree and the list of path components in |*comps|."""
- if not self._webkit_base_dir:
- abspath = os.path.abspath(__file__)
- self._webkit_base_dir = abspath[0:abspath.find('WebKitTools')]
-
- return os.path.join(self._webkit_base_dir, *comps)
+ return self._config.path_from_webkit_base(*comps)
- # FIXME: Callers should eventually move to scm.script_path.
def script_path(self, script_name):
- return self.path_from_webkit_base("WebKitTools", "Scripts", script_name)
+ return self._config.script_path(script_name)
def path_to_test_expectations_file(self):
"""Update the test expectations to the passed-in string.
@@ -726,50 +715,8 @@ class Port(object):
e.message_with_output()))
return self._pretty_patch_error_html
- def _webkit_build_directory_command(self, args):
- return ["perl", self.script_path("webkit-build-directory")] + args
-
- @memoized
- def _webkit_top_level_build_directory(self, top_level=True):
- """This directory is above where products are built to and contains things like the Configuration file."""
- args = self._webkit_build_directory_command(["--top-level"])
- return self._executive.run_command(args).rstrip()
-
- @memoized
- def _webkit_configuration_build_directory(self, configuration=None):
- """This is where products are normally built to."""
- if not configuration:
- configuration = self.flag_from_configuration(self.get_option('configuration'))
- args = self._webkit_build_directory_command(["--configuration", configuration])
- return self._executive.run_command(args).rstrip()
-
- def _configuration_file_path(self):
- return os.path.join(self._webkit_top_level_build_directory(), "Configuration")
-
- # Easy override for unit tests
- def _open_configuration_file(self):
- configuration_path = self._configuration_file_path()
- return codecs.open(configuration_path, "r", "utf-8")
-
- def _read_configuration(self):
- try:
- with self._open_configuration_file() as file:
- return file.readline().rstrip()
- except:
- return None
-
- # FIXME: This list may be incomplete as Apple has some sekret configs.
- _RECOGNIZED_CONFIGURATIONS = ("Debug", "Release")
-
def default_configuration(self):
- # FIXME: Unify this with webkitdir.pm configuration reading code.
- configuration = self._read_configuration()
- if not configuration:
- configuration = "Release"
- if configuration not in self._RECOGNIZED_CONFIGURATIONS:
- _log.warn("Configuration \"%s\" found in %s is not a recognized value.\n" % (configuration, self._configuration_file_path()))
- _log.warn("Scripts may fail. See 'set-webkit-configuration --help'.")
- return configuration
+ return self._config.default_configuration()
#
# PROTECTED ROUTINES
@@ -777,6 +724,8 @@ class Port(object):
# The routines below should only be called by routines in this class
# or any of its subclasses.
#
+ def _webkit_build_directory(self, args):
+ return self._config.build_directory(args[0])
def _path_to_apache(self):
"""Returns the full path to the apache binary.
@@ -848,8 +797,8 @@ class Port(object):
def _webkit_baseline_path(self, platform):
"""Return the full path to the top of the baseline tree for a
given platform."""
- return os.path.join(self.layout_tests_dir(), 'platform',
- platform)
+ return self._filesystem.join(self.layout_tests_dir(), 'platform',
+ platform)
class Driver:
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/base_unittest.py
index ee868e8..1e9c2b7 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/base_unittest.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/base_unittest.py
@@ -28,49 +28,21 @@
import optparse
import os
-import StringIO
import sys
import tempfile
import unittest
-from webkitpy.common.system.path import abspath_to_uri
from webkitpy.common.system.executive import Executive, ScriptError
+from webkitpy.common.system import executive_mock
+from webkitpy.common.system import filesystem
+from webkitpy.common.system import outputcapture
+from webkitpy.common.system.path import abspath_to_uri
from webkitpy.thirdparty.mock import Mock
from webkitpy.tool import mocktool
import base
-
-# FIXME: This makes StringIO objects work with "with". Remove
-# when we upgrade to 2.6.
-class NewStringIO(StringIO.StringIO):
- def __enter__(self):
- return self
-
- def __exit__(self, type, value, traceback):
- pass
-
-
-class MockExecutive():
- def __init__(self, exception):
- self._exception = exception
-
- def run_command(self, *args, **kwargs):
- raise self._exception
-
-
-class UnitTestPort(base.Port):
- """Subclass of base.Port used for unit testing."""
- def __init__(self, configuration_contents=None, configuration_exception=IOError, executive_exception=None):
- base.Port.__init__(self)
- self._configuration_contents = configuration_contents
- self._configuration_exception = configuration_exception
- if executive_exception:
- self._executive = MockExecutive(executive_exception)
-
- def _open_configuration_file(self):
- if self._configuration_contents:
- return NewStringIO(self._configuration_contents)
- raise self._configuration_exception
+import config
+import config_mock
class PortTest(unittest.TestCase):
@@ -102,18 +74,21 @@ class PortTest(unittest.TestCase):
return new_file
def test_pretty_patch_os_error(self):
- port = UnitTestPort(executive_exception=OSError)
+ port = base.Port(executive=executive_mock.MockExecutive2(exception=OSError))
+ oc = outputcapture.OutputCapture()
+ oc.capture_output()
self.assertEqual(port.pretty_patch_text("patch.txt"),
port._pretty_patch_error_html)
# This tests repeated calls to make sure we cache the result.
self.assertEqual(port.pretty_patch_text("patch.txt"),
port._pretty_patch_error_html)
+ oc.restore_output()
def test_pretty_patch_script_error(self):
# FIXME: This is some ugly white-box test hacking ...
base._pretty_patch_available = True
- port = UnitTestPort(executive_exception=ScriptError)
+ port = base.Port(executive=executive_mock.MockExecutive2(exception=ScriptError))
self.assertEqual(port.pretty_patch_text("patch.txt"),
port._pretty_patch_error_html)
@@ -194,13 +169,9 @@ class PortTest(unittest.TestCase):
self.assertFalse('nosuchthing' in diff)
def test_default_configuration_notfound(self):
- # Regular IOError thrown while trying to get the configuration.
- port = UnitTestPort()
- self.assertEqual(port.default_configuration(), "Release")
-
- # More exotic OSError thrown.
- port = UnitTestPort(configuration_exception=OSError)
- self.assertEqual(port.default_configuration(), "Release")
+ # Test that we delegate to the config object properly.
+ port = base.Port(config=config_mock.MockConfig(default_configuration='default'))
+ self.assertEqual(port.default_configuration(), 'default')
def test_layout_tests_skipping(self):
port = base.Port()
@@ -209,14 +180,6 @@ class PortTest(unittest.TestCase):
self.assertTrue(port.skips_layout_test('media/video-zoom.html'))
self.assertFalse(port.skips_layout_test('foo/foo.html'))
- def test_default_configuration_found(self):
- port = UnitTestPort(configuration_contents="Debug")
- self.assertEqual(port.default_configuration(), "Debug")
-
- def test_default_configuration_unknown(self):
- port = UnitTestPort(configuration_contents="weird_value")
- self.assertEqual(port.default_configuration(), "weird_value")
-
def test_setup_test_run(self):
port = base.Port()
# This routine is a no-op. We just test it for coverage.
@@ -229,7 +192,6 @@ class PortTest(unittest.TestCase):
self.assertTrue('css2.1' in dirs)
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")
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/config.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/config.py
index 2364098..4a0de96 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/config.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/config.py
@@ -32,12 +32,8 @@
# FIXME: This file needs to be unified with common/checkout/scm.py and
# common/config/ports.py .
-from __future__ import with_statement
-
-import codecs
import os
-from webkitpy.common.checkout import scm
from webkitpy.common.system import logutils
@@ -62,8 +58,9 @@ class Config(object):
"Release": "--release",
}
- def __init__(self, executive):
+ def __init__(self, executive, filesystem):
self._executive = executive
+ self._filesystem = filesystem
self._webkit_base_dir = None
self._default_configuration = None
self._build_directories = {}
@@ -115,28 +112,36 @@ class Config(object):
return self._default_configuration
def path_from_webkit_base(self, *comps):
- return os.path.join(self.webkit_base_dir(), *comps)
+ return self._filesystem.join(self.webkit_base_dir(), *comps)
def webkit_base_dir(self):
"""Returns the absolute path to the top of the WebKit tree.
Raises an AssertionError if the top dir can't be determined."""
- # FIXME: Consider determining this independently of scm in order
- # to be able to run in a bare tree.
+ # Note: this code somewhat duplicates the code in
+ # scm.find_checkout_root(). However, that code only works if the top
+ # of the SCM repository also matches the top of the WebKit tree. The
+ # Chromium ports, for example, only check out subdirectories like
+ # WebKitTools/Scripts, and so we still have to do additional work
+ # to find the top of the tree.
+ #
+ # This code will also work if there is no SCM system at all.
if not self._webkit_base_dir:
- self._webkit_base_dir = scm.find_checkout_root()
- assert self._webkit_base_dir, "Could not determine the top of the WebKit checkout"
+ abspath = os.path.abspath(__file__)
+ self._webkit_base_dir = abspath[0:abspath.find('WebKitTools')]
return self._webkit_base_dir
def _script_path(self, script_name):
- return os.path.join(self.webkit_base_dir(), "WebKitTools",
- "Scripts", script_name)
+ return self._filesystem.join(self.webkit_base_dir(), "WebKitTools",
+ "Scripts", script_name)
def _determine_configuration(self):
# This mirrors the logic in webkitdirs.pm:determineConfiguration().
global _determined_configuration
if _determined_configuration == -1:
contents = self._read_configuration()
+ if not contents:
+ contents = "Release"
if contents == "Deployment":
contents = "Release"
if contents == "Development":
@@ -145,10 +150,9 @@ class Config(object):
return _determined_configuration
def _read_configuration(self):
- configuration_path = os.path.join(self.build_directory(None),
- "Configuration")
- if not os.path.exists(configuration_path):
+ configuration_path = self._filesystem.join(self.build_directory(None),
+ "Configuration")
+ if not self._filesystem.exists(configuration_path):
return None
- with codecs.open(configuration_path, "r", "utf-8") as fh:
- return fh.read().rstrip()
+ return self._filesystem.read_text_file(configuration_path).rstrip()
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/config_mock.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/config_mock.py
new file mode 100644
index 0000000..af71fa3
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/config_mock.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Wrapper objects for WebKit-specific utility routines."""
+
+
+class MockConfig(object):
+ def __init__(self, default_configuration='Release'):
+ self._default_configuration = default_configuration
+
+ def build_directory(self, configuration):
+ return "/build"
+
+ def build_dumprendertree(self, configuration):
+ return True
+
+ def default_configuration(self):
+ return self._default_configuration
+
+ def path_from_webkit_base(self, *comps):
+ return "/" + "/".join(list(comps))
+
+ def webkit_base_dir(self):
+ return "/"
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/config_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/config_unittest.py
index 4674cba..ed5ab8b 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/config_unittest.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/config_unittest.py
@@ -26,150 +26,120 @@
# (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 StringIO
import unittest
+from webkitpy.common.system import executive
+from webkitpy.common.system import executive_mock
+from webkitpy.common.system import filesystem
+from webkitpy.common.system import filesystem_mock
from webkitpy.common.system import outputcapture
import config
-
-# FIXME: This makes StringIO objects work with "with". Remove
-# when we upgrade to 2.6.
-class NewStringIO(StringIO.StringIO):
- def __enter__(self):
- return self
-
- def __exit__(self, type, value, traceback):
- pass
-
-
-class MockExecutive(object):
- def __init__(self, output='', exit_code=0):
- self._output = output
- self._exit_code = exit_code
-
- def run_command(self, arg_list, return_exit_code=False,
- decode_output=False):
- if return_exit_code:
- return self._exit_code
- return self._output
-
-
class ConfigTest(unittest.TestCase):
def tearDown(self):
config.clear_cached_configuration()
- def assertConfiguration(self, contents, expected):
+ def make_config(self, output='', files={}, exit_code=0):
+ e = executive_mock.MockExecutive2(output=output, exit_code=exit_code)
+ fs = filesystem_mock.MockFileSystem(files)
+ return config.Config(e, fs)
+
+ def assert_configuration(self, contents, expected):
# This tests that a configuration file containing
# _contents_ endsd up being interpreted as _expected_.
- #
- # FIXME: rewrite this when we have a filesystem abstraction we
- # can mock out more easily.
- config.clear_cached_configuration()
- orig_open = codecs.open
-
- def wrap_open(contents):
- def open_wrapper(path, mode, encoding):
- return NewStringIO(contents)
- return open_wrapper
-
- try:
- orig_exists = os.path.exists
- os.path.exists = lambda p: True
- codecs.open = wrap_open(contents)
-
- e = MockExecutive(output='foo')
- c = config.Config(e)
- self.assertEqual(c.default_configuration(), expected)
- finally:
- os.path.exists = orig_exists
- codecs.open = orig_open
+ c = self.make_config('foo', {'foo/Configuration': contents})
+ self.assertEqual(c.default_configuration(), expected)
def test_build_directory_toplevel(self):
- e = MockExecutive(output="toplevel")
- c = config.Config(e)
+ c = self.make_config('toplevel')
self.assertEqual(c.build_directory(None), 'toplevel')
# Test again to check caching
self.assertEqual(c.build_directory(None), 'toplevel')
def test_build_directory__release(self):
- e = MockExecutive(output="release")
- c = config.Config(e)
+ c = self.make_config('release')
self.assertEqual(c.build_directory('Release'), 'release')
def test_build_directory__debug(self):
- e = MockExecutive(output="debug")
- c = config.Config(e)
+ c = self.make_config('debug')
self.assertEqual(c.build_directory('Debug'), 'debug')
def test_build_directory__unknown(self):
- e = MockExecutive(output="unknown")
- c = config.Config(e)
+ c = self.make_config("unknown")
self.assertRaises(KeyError, c.build_directory, 'Unknown')
def test_build_dumprendertree__success(self):
- e = MockExecutive(exit_code=0)
- c = config.Config(e)
+ c = self.make_config(exit_code=0)
self.assertTrue(c.build_dumprendertree("Debug"))
self.assertTrue(c.build_dumprendertree("Release"))
self.assertRaises(KeyError, c.build_dumprendertree, "Unknown")
def test_build_dumprendertree__failure(self):
- e = MockExecutive(exit_code=-1)
- c = config.Config(e)
+ c = self.make_config(exit_code=-1)
+ # FIXME: Build failures should log errors. However, the message we
+ # get depends on how we're being called; as a standalone test,
+ # we'll get the "no handlers found" message. As part of
+ # test-webkitpy, we get the actual message. Really, we need
+ # outputcapture to install its own handler.
oc = outputcapture.OutputCapture()
oc.capture_output()
self.assertFalse(c.build_dumprendertree('Debug'))
- (out, err) = oc.restore_output()
+ oc.restore_output()
oc.capture_output()
self.assertFalse(c.build_dumprendertree('Release'))
oc.restore_output()
def test_default_configuration__release(self):
- self.assertConfiguration('Release', 'Release')
+ self.assert_configuration('Release', 'Release')
def test_default_configuration__debug(self):
- self.assertConfiguration('Debug', 'Debug')
+ self.assert_configuration('Debug', 'Debug')
def test_default_configuration__deployment(self):
- self.assertConfiguration('Deployment', 'Release')
+ self.assert_configuration('Deployment', 'Release')
def test_default_configuration__development(self):
- self.assertConfiguration('Development', 'Debug')
+ self.assert_configuration('Development', 'Debug')
def test_default_configuration__notfound(self):
# This tests what happens if the default configuration file
# doesn't exist.
- config.clear_cached_configuration()
- try:
- orig_exists = os.path.exists
- os.path.exists = lambda p: False
- e = MockExecutive(output="foo")
- c = config.Config(e)
- self.assertEqual(c.default_configuration(), "Release")
- finally:
- os.path.exists = orig_exists
+ c = self.make_config(output='foo', files={'foo/Configuration': None})
+ self.assertEqual(c.default_configuration(), "Release")
def test_default_configuration__unknown(self):
# Ignore the warning about an unknown configuration value.
oc = outputcapture.OutputCapture()
oc.capture_output()
- self.assertConfiguration('Unknown', 'Unknown')
+ self.assert_configuration('Unknown', 'Unknown')
oc.restore_output()
- def test_path_from_webkit_base(self, *comps):
- c = config.Config(None)
+ def test_path_from_webkit_base(self):
+ # FIXME: We use a real filesystem here. Should this move to a
+ # mocked one?
+ c = config.Config(executive.Executive(), filesystem.FileSystem())
self.assertTrue(c.path_from_webkit_base('foo'))
def test_webkit_base_dir(self):
- c = config.Config(None)
- self.assertTrue(c.webkit_base_dir())
+ # FIXME: We use a real filesystem here. Should this move to a
+ # mocked one?
+ c = config.Config(executive.Executive(), filesystem.FileSystem())
+ base_dir = c.webkit_base_dir()
+ self.assertTrue(base_dir)
+
+ orig_cwd = os.getcwd()
+ os.chdir(os.environ['HOME'])
+ c = config.Config(executive.Executive(), filesystem.FileSystem())
+ try:
+ base_dir_2 = c.webkit_base_dir()
+ self.assertEqual(base_dir, base_dir_2)
+ finally:
+ os.chdir(orig_cwd)
if __name__ == '__main__':
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py
index c4c885d..e60c274 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py
@@ -28,7 +28,8 @@ import codecs
import os
import unittest
-import base_unittest
+from webkitpy.common import newstringio
+
import factory
import google_chrome
@@ -77,7 +78,7 @@ class GetGoogleChromePortTest(unittest.TestCase):
def mock_open(path, mode, encoding):
if 'test_expectations_chrome.txt' in path:
- return base_unittest.NewStringIO(expected_string)
+ return newstringio.StringIO(expected_string)
return orig_open(path, mode, encoding)
try:
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit.py
index 0b324f5..51f57c4 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit.py
@@ -81,14 +81,8 @@ class WebKitPort(base.Port):
return ''
def _build_driver(self):
- exit_code = self._executive.run_command([
- self.script_path("build-dumprendertree"),
- self.flag_from_configuration(self.get_option('configuration')),
- ], return_exit_code=True)
- if exit_code != 0:
- _log.error("Failed to build DumpRenderTree")
- return False
- return True
+ configuration = self.get_option('configuration')
+ return self._config.build_dumprendertree(configuration)
def _check_driver(self):
driver_path = self._path_to_driver()
@@ -357,8 +351,8 @@ class WebKitPort(base.Port):
'mac-tiger', 'mac-leopard', 'mac-snowleopard')
def _build_path(self, *comps):
- build_root = self._webkit_configuration_build_directory()
- return os.path.join(build_root, *comps)
+ return self._filesystem.join(self._config.build_directory(
+ self.get_option('configuration')), *comps)
def _path_to_driver(self):
return self._build_path('DumpRenderTree')
diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
index f21e7a5..248a291 100644
--- a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
+++ b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
@@ -380,31 +380,30 @@ class RebaselineTest(unittest.TestCase):
baseline = file + "-expected" + ext
self.assertTrue(any(f.find(baseline) != -1 for f in file_list))
- # FIXME: This test is failing on the bots. Also, this test touches the
- # file system. Unit tests should not read or write the file system.
- # https://bugs.webkit.org/show_bug.cgi?id=47879
def disabled_test_reset_results(self):
+ # FIXME: This test is disabled until we can rewrite it to use a
+ # mock filesystem.
+ #
+ # Test that we update expectations in place. If the expectation
+ # is missing, update the expected generic location.
file_list = []
- original_open = codecs.open
- try:
- # Test that we update expectations in place. If the expectation
- # is missing, update the expected generic location.
- file_list = []
- codecs.open = _mocked_open(original_open, file_list)
- passing_run(['--pixel-tests',
- '--reset-results',
- 'passes/image.html',
- 'failures/expected/missing_image.html'],
- tests_included=True)
- self.assertEqual(len(file_list), 6)
- self.assertBaselines(file_list,
- "data/passes/image")
- self.assertBaselines(file_list,
- "data/failures/expected/missing_image")
- finally:
- codecs.open = original_open
-
- def test_new_baseline(self):
+ passing_run(['--pixel-tests',
+ '--reset-results',
+ 'passes/image.html',
+ 'failures/expected/missing_image.html'],
+ tests_included=True)
+ self.assertEqual(len(file_list), 6)
+ self.assertBaselines(file_list,
+ "data/passes/image")
+ self.assertBaselines(file_list,
+ "data/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.
+ #
+ # 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:
diff --git a/WebKitTools/Scripts/webkitpy/tool/mocktool.py b/WebKitTools/Scripts/webkitpy/tool/mocktool.py
index b6ee95f..719f9b1 100644
--- a/WebKitTools/Scripts/webkitpy/tool/mocktool.py
+++ b/WebKitTools/Scripts/webkitpy/tool/mocktool.py
@@ -571,6 +571,7 @@ class MockStatusServer(object):
# FIXME: This should not inherit from Mock
+# FIXME: Unify with common.system.executive_mock.MockExecutive.
class MockExecutive(Mock):
def __init__(self, should_log):
self._should_log = should_log
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list