diff options
Diffstat (limited to 'Tools/Scripts/webkitpy')
21 files changed, 644 insertions, 678 deletions
diff --git a/Tools/Scripts/webkitpy/common/config/committers.py b/Tools/Scripts/webkitpy/common/config/committers.py index 4a55d495c..efa5aac89 100644 --- a/Tools/Scripts/webkitpy/common/config/committers.py +++ b/Tools/Scripts/webkitpy/common/config/committers.py @@ -113,6 +113,7 @@ contributors_who_are_not_committers = [ Contributor("Alexandre Elias", "aelias@chromium.org"), Contributor("Alexey Marinichev", ["amarinichev@chromium.org", "amarinichev@google.com"], "amarinichev"), Contributor("Andras Piroska", "pandras@inf.u-szeged.hu", "andris88"), + Contributor("Andrei Bucur", "abucur@adobe.com", "abucur"), Contributor("Anne van Kesteren", "annevankesteren+webkit@gmail.com", "annevk"), Contributor("Annie Sullivan", "sullivan@chromium.org", "annie"), Contributor("Aryeh Gregor", "ayg@aryeh.name", "AryehGregor"), @@ -142,12 +143,15 @@ contributors_who_are_not_committers = [ Contributor("John Mellor", "johnme@chromium.org"), Contributor("Kulanthaivel Palanichamy", "kulanthaivel@codeaurora.org", "kvel"), Contributor(u"Michael Br\u00fcning", "michael.bruning@nokia.com", "mibrunin"), + Contributor("Mihai Balan", "mibalan@adobe.com", "miChou"), Contributor("Min Qin", "qinmin@chromium.org"), Contributor("Nandor Huszka", "hnandor@inf.u-szeged.hu", "hnandor"), Contributor("Oliver Varga", ["voliver@inf.u-szeged.hu", "Varga.Oliver@stud.u-szeged.hu"], "TwistO"), Contributor("Peter Gal", "galpeter@inf.u-szeged.hu", "elecro"), Contributor("Peter Linss", "peter.linss@hp.com", "plinss"), + Contributor("Pravin D", "pravind.2k4@gmail.com", 'pravind'), Contributor("Radar WebKit Bug Importer", "webkit-bug-importer@group.apple.com"), + Contributor("Raul Hudea", "rhudea@adobe.com", "rhudea"), Contributor("Roland Takacs", "rtakacs@inf.u-szeged.hu", "rtakacs"), Contributor("Szilard Ledan-Muntean", "szledan@inf.u-szeged.hu", "szledan"), Contributor("Tab Atkins", ["tabatkins@google.com", "jackalmage@gmail.com"], "tabatkins"), diff --git a/Tools/Scripts/webkitpy/common/system/executive.py b/Tools/Scripts/webkitpy/common/system/executive.py index cb36b5dc0..1099e07fb 100644 --- a/Tools/Scripts/webkitpy/common/system/executive.py +++ b/Tools/Scripts/webkitpy/common/system/executive.py @@ -27,10 +27,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 multiprocessing -import ctypes import errno import logging +import multiprocessing import os import StringIO import signal @@ -211,12 +210,18 @@ class Executive(object): continue if e.errno == errno.ESRCH: # The process does not exist. return + if e.errno == errno.EPIPE: # The process has exited already on cygwin + return if e.errno == errno.ECHILD: # Can't wait on a non-child process, but the kill worked. return raise def _win32_check_running_pid(self, pid): + # importing ctypes at the top-level seems to cause weird crashes at + # exit under cygwin on apple's win port. Only win32 needs cygwin, so + # we import it here instead. See https://bugs.webkit.org/show_bug.cgi?id=91682 + import ctypes class PROCESSENTRY32(ctypes.Structure): _fields_ = [("dwSize", ctypes.c_ulong), diff --git a/Tools/Scripts/webkitpy/common/system/executive_unittest.py b/Tools/Scripts/webkitpy/common/system/executive_unittest.py index 212896a4a..c041b6372 100644 --- a/Tools/Scripts/webkitpy/common/system/executive_unittest.py +++ b/Tools/Scripts/webkitpy/common/system/executive_unittest.py @@ -28,6 +28,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import os +import errno import signal import subprocess import sys @@ -77,8 +78,6 @@ def command_line(cmd, *args): class ExecutiveTest(unittest.TestCase): def assert_interpreter_for_content(self, intepreter, content): fs = MockFileSystem() - file_path = None - file_interpreter = None tempfile, temp_name = fs.open_binary_tempfile('') tempfile.write(content) @@ -166,26 +165,12 @@ class ExecutiveTest(unittest.TestCase): else: expected_exit_code = -signal.SIGKILL self.assertEqual(process.wait(), expected_exit_code) + # Killing again should fail silently. executive.kill_process(process.pid) - def _assert_windows_image_name(self, name, expected_windows_name): - executive = Executive() - windows_name = executive._windows_image_name(name) - self.assertEqual(windows_name, expected_windows_name) - - def test_windows_image_name(self): - self._assert_windows_image_name("foo", "foo.exe") - self._assert_windows_image_name("foo.exe", "foo.exe") - self._assert_windows_image_name("foo.com", "foo.com") - # If the name looks like an extension, even if it isn't - # supposed to, we have no choice but to return the original name. - self._assert_windows_image_name("foo.baz", "foo.baz") - self._assert_windows_image_name("foo.baz.exe", "foo.baz.exe") - - def test_kill_all(self): - executive = Executive() - # We use "yes" because it loops forever. + # Now test kill_all ; we do this in the same test as kill + # so that we don't collide when running tests in parallel. process = subprocess.Popen(never_ending_command(), stdout=subprocess.PIPE) self.assertEqual(process.poll(), None) # Process is running executive.kill_all(never_ending_command()[0]) @@ -203,6 +188,20 @@ class ExecutiveTest(unittest.TestCase): # Killing again should fail silently. executive.kill_all(never_ending_command()[0]) + def _assert_windows_image_name(self, name, expected_windows_name): + executive = Executive() + windows_name = executive._windows_image_name(name) + self.assertEqual(windows_name, expected_windows_name) + + def test_windows_image_name(self): + self._assert_windows_image_name("foo", "foo.exe") + self._assert_windows_image_name("foo.exe", "foo.exe") + self._assert_windows_image_name("foo.com", "foo.com") + # If the name looks like an extension, even if it isn't + # supposed to, we have no choice but to return the original name. + self._assert_windows_image_name("foo.baz", "foo.baz") + self._assert_windows_image_name("foo.baz.exe", "foo.baz.exe") + def test_check_running_pid(self): executive = Executive() self.assertTrue(executive.check_running_pid(os.getpid())) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base.py b/Tools/Scripts/webkitpy/layout_tests/port/base.py index dda129f2f..d79143189 100755 --- a/Tools/Scripts/webkitpy/layout_tests/port/base.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/base.py @@ -36,6 +36,7 @@ import errno import os import optparse import re +import sys try: from collections import OrderedDict @@ -184,12 +185,39 @@ class Port(object): def baseline_search_path(self): """Return a list of absolute paths to directories to search under for baselines. The directories are searched in order.""" - raise NotImplementedError('Port.baseline_search_path') + search_paths = [] + if self.get_option('webkit_test_runner'): + search_paths.append(self._wk2_port_name()) + search_paths.append(self.name()) + if self.name() != self.port_name: + search_paths.append(self.port_name) + return map(self._webkit_baseline_path, search_paths) def check_build(self, needs_http): """This routine is used to ensure that the build is up to date and all the needed binaries are present.""" - raise NotImplementedError('Port.check_build') + # If we're using a pre-built copy of WebKit (--root), we assume it also includes a build of DRT. + if not self.get_option('root') and self.get_option('build') and not self._build_driver(): + return False + if not self._check_driver(): + return False + if self.get_option('pixel_tests'): + if not self.check_image_diff(): + return False + if not self._check_port_build(): + return False + return True + + def _check_driver(self): + driver_path = self._path_to_driver() + if not self._filesystem.exists(driver_path): + _log.error("%s was not found at %s" % (self.driver_name(), driver_path)) + return False + return True + + def _check_port_build(self): + # Ports can override this method to do additional checks. + return True def check_sys_deps(self, needs_http): """If the port needs to do some runtime checks to ensure that the @@ -203,7 +231,11 @@ class Port(object): def check_image_diff(self, override_step=None, logging=True): """This routine is used to check whether image_diff binary exists.""" - raise NotImplementedError('Port.check_image_diff') + image_diff_path = self._path_to_image_diff() + if not self._filesystem.exists(image_diff_path): + _log.error("ImageDiff was not found at %s" % image_diff_path) + return False + return True def check_pretty_patch(self, logging=True): """Checks whether we can use the PrettyPatch ruby script.""" @@ -308,9 +340,10 @@ class Port(object): pass def driver_name(self): - # FIXME: Seems we should get this from the Port's Driver class. if self.get_option('driver_name'): return self.get_option('driver_name') + if self.get_option('webkit_test_runner'): + return 'WebKitTestRunner' return 'DumpRenderTree' def expected_baselines_by_extension(self, test_name): @@ -733,7 +766,9 @@ class Port(object): def default_results_directory(self): """Absolute path to the default place to store the test results.""" - raise NotImplementedError() + # Results are store relative to the built products to make it easy + # to have multiple copies of webkit checked out and built. + return self._build_path('layout-test-results') def setup_test_run(self): """Perform port-specific work at the beginning of a test run.""" @@ -777,12 +812,20 @@ class Port(object): # Windows: 'PATH', + + # Most ports (?): + 'WEBKIT_TESTFONTS', ] for variable in variables_to_copy: self._copy_value_from_environ_if_set(clean_env, variable) # For Linux: clean_env['DISPLAY'] = self._value_or_default_from_environ('DISPLAY', ':1') + + for string_variable in self.get_option('additional_env_var', []): + [name, value] = string_variable.split('=', 1) + clean_env[name] = value + return clean_env def show_results_html_file(self, results_filename): @@ -1038,25 +1081,63 @@ class Port(object): def _uses_apache(self): return True + # FIXME: This does not belong on the port object. + @memoized def _path_to_apache(self): """Returns the full path to the apache binary. This is needed only by ports that use the apache_http_server module.""" - raise NotImplementedError('Port.path_to_apache') + # The Apache binary path can vary depending on OS and distribution + # See http://wiki.apache.org/httpd/DistrosDefaultLayout + for path in ["/usr/sbin/httpd", "/usr/sbin/apache2"]: + if self._filesystem.exists(path): + return path + _log.error("Could not find apache. Not installed or unknown path.") + return None + + # FIXME: This belongs on some platform abstraction instead of Port. + def _is_redhat_based(self): + return self._filesystem.exists('/etc/redhat-release') + + def _is_debian_based(self): + return self._filesystem.exists('/etc/debian_version') + + # We pass sys_platform into this method to make it easy to unit test. + def _apache_config_file_name_for_platform(self, sys_platform): + if sys_platform == 'cygwin': + return 'cygwin-httpd.conf' # CYGWIN is the only platform to still use Apache 1.3. + if sys_platform.startswith('linux'): + if self._is_redhat_based(): + return 'fedora-httpd.conf' # This is an Apache 2.x config file despite the naming. + if self._is_debian_based(): + return 'apache2-debian-httpd.conf' + # All platforms use apache2 except for CYGWIN (and Mac OS X Tiger and prior, which we no longer support). + return "apache2-httpd.conf" def _path_to_apache_config_file(self): """Returns the full path to the apache binary. This is needed only by ports that use the apache_http_server module.""" - raise NotImplementedError('Port.path_to_apache_config_file') + config_file_name = self._apache_config_file_name_for_platform(sys.platform) + return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', config_file_name) + + def _build_path(self, *comps): + # --root is used for running with a pre-built root (like from a nightly zip). + build_directory = self.get_option('root') or self.get_option('build_directory') + if not build_directory: + build_directory = self._config.build_directory(self.get_option('configuration')) + # Set --build-directory here Since this modifies the options object used by the worker subprocesses, + # it avoids the slow call out to build_directory in each subprocess. + self.set_option_default('build_directory', build_directory) + return self._filesystem.join(self._filesystem.abspath(build_directory), *comps) def _path_to_driver(self, configuration=None): """Returns the full path to the test driver (DumpRenderTree).""" - raise NotImplementedError('Port._path_to_driver') + return self._build_path(self.driver_name()) def _path_to_webcore_library(self): """Returns the full path to a built copy of WebCore.""" - raise NotImplementedError('Port.path_to_webcore_library') + return None def _path_to_helper(self): """Returns the full path to the layout_test_helper binary, which @@ -1064,13 +1145,13 @@ class Port(object): if no helper is needed. This is likely only used by start/stop_helper().""" - raise NotImplementedError('Port._path_to_helper') + return None def _path_to_image_diff(self): """Returns the full path to the image_diff binary, or None if it is not available. This is likely used only by diff_image()""" - raise NotImplementedError('Port.path_to_image_diff') + return self._build_path('ImageDiff') def _path_to_lighttpd(self): """Returns the path to the LigHTTPd binary. @@ -1094,7 +1175,7 @@ class Port(object): """Returns the full path to the wdiff binary, or None if it is not available. This is likely used only by wdiff_text()""" - raise NotImplementedError('Port._path_to_wdiff') + return 'wdiff' def _webkit_baseline_path(self, platform): """Return the full path to the top of the baseline tree for a @@ -1109,7 +1190,7 @@ class Port(object): def _driver_class(self): """Returns the port's driver implementation.""" - raise NotImplementedError('Port._driver_class') + return driver.Driver def _get_crash_log(self, name, pid, stdout, stderr, newer_than): name_str = name or '<unknown process name>' diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py index f7afb7b22..7e9259bd3 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py @@ -287,6 +287,14 @@ class PortTest(unittest.TestCase): '/tmp/additional-expectations-1.txt', '/tmp/additional-expectations-2.txt'] self.assertEquals('\n'.join(port.expectations_dict().values()), '\ncontent1\n\ncontent2\n') + def test_additional_env_var(self): + port = self.make_port(options=optparse.Values({'additional_env_var': ['FOO=BAR', 'BAR=FOO']})) + self.assertEqual(port.get_option('additional_env_var'), ['FOO=BAR', 'BAR=FOO']) + environment = port.setup_environ_for_server() + self.assertTrue(('FOO' in environment) & ('BAR' in environment)) + self.assertEqual(environment['FOO'], 'BAR') + self.assertEqual(environment['BAR'], 'FOO') + def test_uses_test_expectations_file(self): port = self.make_port(port_name='foo') port.port_name = 'foo' @@ -383,28 +391,6 @@ class PortTest(unittest.TestCase): _, _, logs = capture.restore_output() self.assertEqual('httpd seems broken. Cannot run http tests.\n', logs) - def assertVirtual(self, method, *args, **kwargs): - self.assertRaises(NotImplementedError, method, *args, **kwargs) - - def test_virtual_methods(self): - port = Port(MockSystemHost()) - self.assertVirtual(port.baseline_path) - self.assertVirtual(port.baseline_search_path) - self.assertVirtual(port.check_build, None) - self.assertVirtual(port.check_image_diff) - self.assertVirtual(port.create_driver, 0) - self.assertVirtual(port.diff_image, None, None) - self.assertVirtual(port.default_results_directory) - self.assertVirtual(port._path_to_apache) - self.assertVirtual(port._path_to_apache_config_file) - self.assertVirtual(port._path_to_driver) - self.assertVirtual(port._path_to_helper) - self.assertVirtual(port._path_to_image_diff) - self.assertVirtual(port._path_to_lighttpd) - self.assertVirtual(port._path_to_lighttpd_modules) - self.assertVirtual(port._path_to_lighttpd_php) - self.assertVirtual(port._path_to_wdiff) - def test_test_exists(self): port = self.make_port(with_tests=True) self.assertTrue(port.test_exists('passes')) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py index 45298c634..9729f94c0 100755 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py @@ -42,8 +42,7 @@ from webkitpy.common.system import executive from webkitpy.common.system.path import cygpath from webkitpy.layout_tests.models.test_configuration import TestConfiguration from webkitpy.layout_tests.port.base import Port, VirtualTestSuite -from webkitpy.layout_tests.port.driver import DriverOutput -from webkitpy.layout_tests.port.webkit import WebKitPort, WebKitDriver +from webkitpy.layout_tests.port.webkit import WebKitPort _log = logging.getLogger(__name__) @@ -140,12 +139,6 @@ class ChromiumPort(WebKitPort): return False return True - def driver_name(self): - # FIXME: merge this with Port.driver_name, WebKitPort.driver_name - if self.get_option('driver_name'): - return self.get_option('driver_name') - return 'DumpRenderTree' - def check_build(self, needs_http): result = True diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py index 126b31868..eb4dcec95 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py @@ -34,6 +34,7 @@ import threading import time from webkitpy.layout_tests.port import chromium +from webkitpy.layout_tests.port import driver from webkitpy.layout_tests.port import factory from webkitpy.layout_tests.port import server_process from webkitpy.layout_tests.port import webkit @@ -57,7 +58,7 @@ DEVICE_DRT_STAMP_PATH = DEVICE_DRT_DIR + 'DumpRenderTree.stamp' DRT_APP_PACKAGE = 'org.chromium.native_test' DRT_ACTIVITY_FULL_NAME = DRT_APP_PACKAGE + '/.ChromeNativeTestActivity' DRT_APP_DIR = '/data/user/0/' + DRT_APP_PACKAGE + '/' -DRT_APP_FILES_DIR = DRT_APP_DIR + 'files/' +DRT_APP_FILES_DIR = DEVICE_SOURCE_ROOT_DIR DRT_APP_CACHE_DIR = DRT_APP_DIR + 'cache/' # This only works for single core devices so far. @@ -456,9 +457,9 @@ class ChromiumAndroidPort(chromium.ChromiumPort): self._original_governor = None -class ChromiumAndroidDriver(webkit.WebKitDriver): +class ChromiumAndroidDriver(driver.Driver): def __init__(self, port, worker_number, pixel_tests, no_timeout=False): - webkit.WebKitDriver.__init__(self, port, worker_number, pixel_tests, no_timeout) + super(ChromiumAndroidDriver, self).__init__(port, worker_number, pixel_tests, no_timeout) self._pixel_tests = pixel_tests self._in_fifo_path = DRT_APP_FILES_DIR + 'DumpRenderTree.in' self._out_fifo_path = DRT_APP_FILES_DIR + 'DumpRenderTree.out' @@ -490,7 +491,7 @@ class ChromiumAndroidDriver(webkit.WebKitDriver): # Otherwise the main thread has been proceeded normally. This thread just exits silently. def _drt_cmd_line(self, pixel_tests, per_test_args): - return webkit.WebKitDriver.cmd_line(self, pixel_tests, per_test_args) + [ + return driver.Driver.cmd_line(self, pixel_tests, per_test_args) + [ '--in-fifo=' + self._in_fifo_path, '--out-fifo=' + self._out_fifo_path, '--err-fifo=' + self._err_fifo_path, diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_android_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_android_unittest.py index a3a3aaeb4..0e2801a57 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_android_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_android_unittest.py @@ -38,7 +38,7 @@ from webkitpy.common.system.systemhost_mock import MockSystemHost from webkitpy.layout_tests.port import chromium_android from webkitpy.layout_tests.port import chromium_port_testcase from webkitpy.layout_tests.port import driver -from webkitpy.layout_tests.port import webkit_unittest +from webkitpy.layout_tests.port import driver_unittest class ChromiumAndroidPortTest(chromium_port_testcase.ChromiumPortTestCase): @@ -147,9 +147,9 @@ class ChromiumAndroidDriverTest(unittest.TestCase): self.assertTrue('--err-fifo=' + chromium_android.DRT_APP_FILES_DIR + 'DumpRenderTree.err' in cmd_line) def test_read_prompt(self): - self.driver._server_process = webkit_unittest.MockServerProcess(['root@android:/ # ']) + self.driver._server_process = driver_unittest.MockServerProcess(lines=['root@android:/ # ']) self.assertEquals(self.driver._read_prompt(time.time() + 1), None) - self.driver._server_process = webkit_unittest.MockServerProcess(['$ ']) + self.driver._server_process = driver_unittest.MockServerProcess(lines=['$ ']) self.assertRaises(AssertionError, self.driver._read_prompt, time.time() + 1) def test_command_from_driver_input(self): diff --git a/Tools/Scripts/webkitpy/layout_tests/port/driver.py b/Tools/Scripts/webkitpy/layout_tests/port/driver.py index f65db2f7b..5e7061bab 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/driver.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/driver.py @@ -26,12 +26,21 @@ # (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 base64 import copy +import logging import re import shlex +import sys +import time from webkitpy.common.system import path +from webkitpy.layout_tests.port import server_process + + +_log = logging.getLogger(__name__) + class DriverInput(object): def __init__(self, test_name, timeout, image_hash, should_run_pixel_test, args=None): @@ -91,7 +100,7 @@ class DriverOutput(object): class Driver(object): - """Abstract interface for the DumpRenderTree interface.""" + """object for running test(s) using DumpRenderTree/WebKitTestRunner.""" def __init__(self, port, worker_number, pixel_tests, no_timeout=False): """Initialize a Driver to subsequently run tests. @@ -106,6 +115,32 @@ class Driver(object): self._worker_number = worker_number self._no_timeout = no_timeout + # overridable for testing. + self._server_process_constructor = server_process.ServerProcess + + self._driver_tempdir = None + # WebKitTestRunner can report back subprocess crashes by printing + # "#CRASHED - PROCESSNAME". Since those can happen at any time + # and ServerProcess won't be aware of them (since the actual tool + # didn't crash, just a subprocess) we record the crashed subprocess name here. + self._crashed_process_name = None + self._crashed_pid = None + + # WebKitTestRunner can report back subprocesses that became unresponsive + # This could mean they crashed. + self._subprocess_was_unresponsive = False + + # stderr reading is scoped on a per-test (not per-block) basis, so we store the accumulated + # stderr output, as well as if we've seen #EOF on this driver instance. + # FIXME: We should probably remove _read_first_block and _read_optional_image_block and + # instead scope these locally in run_test. + self.error_from_test = str() + self.err_seen_eof = False + self._server_process = None + + def __del__(self): + self.stop() + def run_test(self, driver_input): """Run a single test and return the results. @@ -115,9 +150,51 @@ class Driver(object): Returns a DriverOuput object. """ - raise NotImplementedError('Driver.run_test') + start_time = time.time() + self.start(driver_input.should_run_pixel_test, driver_input.args) + test_begin_time = time.time() + self.error_from_test = str() + self.err_seen_eof = False + + command = self._command_from_driver_input(driver_input) + deadline = test_begin_time + int(driver_input.timeout) / 1000.0 + + self._server_process.write(command) + text, audio = self._read_first_block(deadline) # First block is either text or audio + image, actual_image_hash = self._read_optional_image_block(deadline) # The second (optional) block is image data. + + # We may not have read all of the output if an error (crash) occured. + # Since some platforms output the stacktrace over error, we should + # dump any buffered error into self.error_from_test. + # FIXME: We may need to also read stderr until the process dies? + self.error_from_test += self._server_process.pop_all_buffered_stderr() + + crash_log = None + if self.has_crashed(): + crash_log = self._port._get_crash_log(self._crashed_process_name, self._crashed_pid, text, self.error_from_test, + newer_than=start_time) + + # If we don't find a crash log use a placeholder error message instead. + if not crash_log: + crash_log = 'no crash log found for %s:%d.' % (self._crashed_process_name, self._crashed_pid) + # If we were unresponsive append a message informing there may not have been a crash. + if self._subprocess_was_unresponsive: + crash_log += ' Process failed to become responsive before timing out.' + + timeout = self._server_process.timed_out + if timeout: + # DRT doesn't have a built in timer to abort the test, so we might as well + # kill the process directly and not wait for it to shut down cleanly (since it may not). + self._server_process.kill() + + return DriverOutput(text, image, actual_image_hash, audio, + crash=self.has_crashed(), test_time=time.time() - test_begin_time, + timeout=timeout, error=self.error_from_test, + crashed_process_name=self._crashed_process_name, + crashed_pid=self._crashed_pid, crash_log=crash_log) # FIXME: Seems this could just be inlined into callers. + @classmethod def _command_wrapper(cls, wrapper_option): # Hook for injecting valgrind or other runtime instrumentation, # used by e.g. tools/valgrind/valgrind_tests.py. @@ -161,17 +238,210 @@ class Driver(object): raise NotImplementedError('unknown url type: %s' % uri) def has_crashed(self): + if self._server_process is None: + return False + if self._crashed_process_name: + return True + if self._server_process.has_crashed(): + self._crashed_process_name = self._server_process.name() + self._crashed_pid = self._server_process.pid() + return True return False - def start(self): - raise NotImplementedError('Driver.start') + def start(self, pixel_tests, per_test_args): + # FIXME: Callers shouldn't normally call this, since this routine + # may not be specifying the correct combination of pixel test and + # per_test args. + # + # The only reason we have this routine at all is so the perftestrunner + # can pause before running a test; it might be better to push that + # into run_test() directly. + if not self._server_process: + self._start(pixel_tests, per_test_args) + + def _start(self, pixel_tests, per_test_args): + self.stop() + self._driver_tempdir = self._port._filesystem.mkdtemp(prefix='%s-' % self._port.driver_name()) + server_name = self._port.driver_name() + environment = self._port.setup_environ_for_server(server_name) + environment['DYLD_LIBRARY_PATH'] = self._port._build_path() + environment['DYLD_FRAMEWORK_PATH'] = self._port._build_path() + # FIXME: We're assuming that WebKitTestRunner checks this DumpRenderTree-named environment variable. + environment['DUMPRENDERTREE_TEMP'] = str(self._driver_tempdir) + environment['LOCAL_RESOURCE_ROOT'] = self._port.layout_tests_dir() + self._crashed_process_name = None + self._crashed_pid = None + self._server_process = self._server_process_constructor(self._port, server_name, self.cmd_line(pixel_tests, per_test_args), environment) + self._server_process.start() def stop(self): - raise NotImplementedError('Driver.stop') + if self._server_process: + self._server_process.stop() + self._server_process = None + + if self._driver_tempdir: + self._port._filesystem.rmtree(str(self._driver_tempdir)) + self._driver_tempdir = None def cmd_line(self, pixel_tests, per_test_args): - raise NotImplementedError('Driver.cmd_line') + cmd = self._command_wrapper(self._port.get_option('wrapper')) + cmd.append(self._port._path_to_driver()) + if self._port.get_option('gc_between_tests'): + cmd.append('--gc-between-tests') + if self._port.get_option('complex_text'): + cmd.append('--complex-text') + if self._port.get_option('threaded'): + cmd.append('--threaded') + if self._no_timeout: + cmd.append('--no-timeout') + # FIXME: We need to pass --timeout=SECONDS to WebKitTestRunner for WebKit2. + + cmd.extend(self._port.get_option('additional_drt_flag', [])) + + if pixel_tests: + cmd.append('--pixel-tests') + cmd.extend(per_test_args) + + cmd.append('-') + return cmd + + def _check_for_driver_crash(self, error_line): + if error_line == "#CRASHED\n": + # This is used on Windows to report that the process has crashed + # See http://trac.webkit.org/changeset/65537. + self._crashed_process_name = self._server_process.name() + self._crashed_pid = self._server_process.pid() + elif (error_line.startswith("#CRASHED - WebProcess") + or error_line.startswith("#PROCESS UNRESPONSIVE - WebProcess")): + # WebKitTestRunner uses this to report that the WebProcess subprocess crashed. + pid = None + m = re.search('pid (\d+)', error_line) + if m: + pid = int(m.group(1)) + self._crashed_process_name = 'WebProcess' + self._crashed_pid = pid + # FIXME: delete this after we're sure this code is working :) + _log.debug('WebProcess crash, pid = %s, error_line = %s' % (str(pid), error_line)) + if error_line.startswith("#PROCESS UNRESPONSIVE - WebProcess"): + self._subprocess_was_unresponsive = True + return True + return self.has_crashed() + + def _command_from_driver_input(self, driver_input): + # FIXME: performance tests pass in full URLs instead of test names. + if driver_input.test_name.startswith('http://') or driver_input.test_name.startswith('https://') or driver_input.test_name == ('about:blank'): + command = driver_input.test_name + elif self.is_http_test(driver_input.test_name): + command = self.test_to_uri(driver_input.test_name) + else: + command = self._port.abspath_for_test(driver_input.test_name) + if sys.platform == 'cygwin': + command = path.cygpath(command) + + if driver_input.image_hash: + # "'" is the separator of command fields. + command += "'" + driver_input.image_hash + return command + "\n" + + def _read_first_block(self, deadline): + # returns (text_content, audio_content) + block = self._read_block(deadline) + if block.content_type == 'audio/wav': + return (None, block.decoded_content) + return (block.decoded_content, None) + + def _read_optional_image_block(self, deadline): + # returns (image, actual_image_hash) + block = self._read_block(deadline, wait_for_stderr_eof=True) + if block.content and block.content_type == 'image/png': + return (block.decoded_content, block.content_hash) + return (None, block.content_hash) + + def _read_header(self, block, line, header_text, header_attr, header_filter=None): + if line.startswith(header_text) and getattr(block, header_attr) is None: + value = line.split()[1] + if header_filter: + value = header_filter(value) + setattr(block, header_attr, value) + return True + return False + def _process_stdout_line(self, block, line): + if (self._read_header(block, line, 'Content-Type: ', 'content_type') + or self._read_header(block, line, 'Content-Transfer-Encoding: ', 'encoding') + or self._read_header(block, line, 'Content-Length: ', '_content_length', int) + or self._read_header(block, line, 'ActualHash: ', 'content_hash')): + return + # Note, we're not reading ExpectedHash: here, but we could. + # If the line wasn't a header, we just append it to the content. + block.content += line + + def _strip_eof(self, line): + if line and line.endswith("#EOF\n"): + return line[:-5], True + return line, False + + def _read_block(self, deadline, wait_for_stderr_eof=False): + block = ContentBlock() + out_seen_eof = False + + while not self.has_crashed(): + if out_seen_eof and (self.err_seen_eof or not wait_for_stderr_eof): + break + + if self.err_seen_eof: + out_line = self._server_process.read_stdout_line(deadline) + err_line = None + elif out_seen_eof: + out_line = None + err_line = self._server_process.read_stderr_line(deadline) + else: + out_line, err_line = self._server_process.read_either_stdout_or_stderr_line(deadline) + + if self._server_process.timed_out or self.has_crashed(): + break + + if out_line: + assert not out_seen_eof + out_line, out_seen_eof = self._strip_eof(out_line) + if err_line: + assert not self.err_seen_eof + err_line, self.err_seen_eof = self._strip_eof(err_line) + + if out_line: + if out_line[-1] != "\n": + _log.error("Last character read from DRT stdout line was not a newline! This indicates either a NRWT or DRT bug.") + content_length_before_header_check = block._content_length + self._process_stdout_line(block, out_line) + # FIXME: Unlike HTTP, DRT dumps the content right after printing a Content-Length header. + # Don't wait until we're done with headers, just read the binary blob right now. + if content_length_before_header_check != block._content_length: + block.content = self._server_process.read_stdout(deadline, block._content_length) + + if err_line: + if self._check_for_driver_crash(err_line): + break + self.error_from_test += err_line + + block.decode_content() + return block + + +class ContentBlock(object): + def __init__(self): + self.content_type = None + self.encoding = None + self.content_hash = None + self._content_length = None + # Content is treated as binary data even though the text output is usually UTF-8. + self.content = str() # FIXME: Should be bytearray() once we require Python 2.6. + self.decoded_content = None + + def decode_content(self): + if self.encoding == 'base64': + self.decoded_content = base64.b64decode(self.content) + else: + self.decoded_content = self.content class DriverProxy(object): """A wrapper for managing two Driver instances, one with pixel tests and diff --git a/Tools/Scripts/webkitpy/layout_tests/port/driver_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/driver_unittest.py index 00a42f42f..d712023e3 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/driver_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/driver_unittest.py @@ -26,13 +26,15 @@ # (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 sys import unittest from webkitpy.common.system.systemhost_mock import MockSystemHost from webkitpy.layout_tests.port import Port, Driver, DriverOutput +# FIXME: remove the dependency on TestWebKitPort +from webkitpy.layout_tests.port.webkit_unittest import TestWebKitPort + class DriverOutputTest(unittest.TestCase): def test_strip_metrics(self): @@ -79,19 +81,10 @@ class DriverTest(unittest.TestCase): def make_port(self): return Port(MockSystemHost()) - def assertVirtual(self, method, *args, **kwargs): - self.assertRaises(NotImplementedError, method, *args, **kwargs) - def _assert_wrapper(self, wrapper_string, expected_wrapper): wrapper = Driver(self.make_port(), None, pixel_tests=False)._command_wrapper(wrapper_string) self.assertEqual(wrapper, expected_wrapper) - def test_virtual_driver_methods(self): - driver = Driver(self.make_port(), None, pixel_tests=False) - self.assertVirtual(driver.run_test, None) - self.assertVirtual(driver.stop) - self.assertVirtual(driver.cmd_line, False, []) - def test_command_wrapper(self): self._assert_wrapper(None, []) self._assert_wrapper("valgrind", ["valgrind"]) @@ -115,6 +108,193 @@ class DriverTest(unittest.TestCase): self.assertEqual(driver.uri_to_test('http://127.0.0.1:8000/foo.html'), 'http/tests/foo.html') self.assertEqual(driver.uri_to_test('https://127.0.0.1:8443/ssl/bar.html'), 'http/tests/ssl/bar.html') + def test_read_block(self): + port = TestWebKitPort() + driver = Driver(port, 0, pixel_tests=False) + driver._server_process = MockServerProcess(lines=[ + 'ActualHash: foobar', + 'Content-Type: my_type', + 'Content-Transfer-Encoding: none', + "#EOF", + ]) + content_block = driver._read_block(0) + self.assertEquals(content_block.content_type, 'my_type') + self.assertEquals(content_block.encoding, 'none') + self.assertEquals(content_block.content_hash, 'foobar') + driver._server_process = None + + def test_read_binary_block(self): + port = TestWebKitPort() + driver = Driver(port, 0, pixel_tests=True) + driver._server_process = MockServerProcess(lines=[ + 'ActualHash: actual', + 'ExpectedHash: expected', + 'Content-Type: image/png', + 'Content-Length: 9', + "12345678", + "#EOF", + ]) + content_block = driver._read_block(0) + self.assertEquals(content_block.content_type, 'image/png') + self.assertEquals(content_block.content_hash, 'actual') + self.assertEquals(content_block.content, '12345678\n') + self.assertEquals(content_block.decoded_content, '12345678\n') + driver._server_process = None + + def test_read_base64_block(self): + port = TestWebKitPort() + driver = Driver(port, 0, pixel_tests=True) + driver._server_process = MockServerProcess(lines=[ + 'ActualHash: actual', + 'ExpectedHash: expected', + 'Content-Type: image/png', + 'Content-Transfer-Encoding: base64', + 'Content-Length: 12', + 'MTIzNDU2NzgK#EOF', + ]) + content_block = driver._read_block(0) + self.assertEquals(content_block.content_type, 'image/png') + self.assertEquals(content_block.content_hash, 'actual') + self.assertEquals(content_block.encoding, 'base64') + self.assertEquals(content_block.content, 'MTIzNDU2NzgK') + self.assertEquals(content_block.decoded_content, '12345678\n') + + def test_no_timeout(self): + port = TestWebKitPort() + driver = Driver(port, 0, pixel_tests=True, no_timeout=True) + self.assertEquals(driver.cmd_line(True, []), ['/mock-build/DumpRenderTree', '--no-timeout', '--pixel-tests', '-']) + + def test_check_for_driver_crash(self): + port = TestWebKitPort() + driver = Driver(port, 0, pixel_tests=True) + + class FakeServerProcess(object): + def __init__(self, crashed): + self.crashed = crashed + + def pid(self): + return 1234 + + def name(self): + return 'FakeServerProcess' + + def has_crashed(self): + return self.crashed + + def stop(self): + pass + + def assert_crash(driver, error_line, crashed, name, pid, unresponsive=False): + self.assertEquals(driver._check_for_driver_crash(error_line), crashed) + self.assertEquals(driver._crashed_process_name, name) + self.assertEquals(driver._crashed_pid, pid) + self.assertEquals(driver._subprocess_was_unresponsive, unresponsive) + driver.stop() + + driver._server_process = FakeServerProcess(False) + assert_crash(driver, '', False, None, None) + + driver._crashed_process_name = None + driver._crashed_pid = None + driver._server_process = FakeServerProcess(False) + driver._subprocess_was_unresponsive = False + assert_crash(driver, '#CRASHED\n', True, 'FakeServerProcess', 1234) + + driver._crashed_process_name = None + driver._crashed_pid = None + driver._server_process = FakeServerProcess(False) + driver._subprocess_was_unresponsive = False + assert_crash(driver, '#CRASHED - WebProcess\n', True, 'WebProcess', None) + + driver._crashed_process_name = None + driver._crashed_pid = None + driver._server_process = FakeServerProcess(False) + driver._subprocess_was_unresponsive = False + assert_crash(driver, '#CRASHED - WebProcess (pid 8675)\n', True, 'WebProcess', 8675) + + driver._crashed_process_name = None + driver._crashed_pid = None + driver._server_process = FakeServerProcess(False) + driver._subprocess_was_unresponsive = False + assert_crash(driver, '#PROCESS UNRESPONSIVE - WebProcess (pid 8675)\n', True, 'WebProcess', 8675, True) + + driver._crashed_process_name = None + driver._crashed_pid = None + driver._server_process = FakeServerProcess(True) + driver._subprocess_was_unresponsive = False + assert_crash(driver, '', True, 'FakeServerProcess', 1234) + + def test_creating_a_port_does_not_write_to_the_filesystem(self): + port = TestWebKitPort() + driver = Driver(port, 0, pixel_tests=True) + self.assertEquals(port._filesystem.written_files, {}) + self.assertEquals(port._filesystem.last_tmpdir, None) + + def test_stop_cleans_up_properly(self): + port = TestWebKitPort() + driver = Driver(port, 0, pixel_tests=True) + driver._server_process_constructor = MockServerProcess + driver.start(True, []) + last_tmpdir = port._filesystem.last_tmpdir + self.assertNotEquals(last_tmpdir, None) + driver.stop() + self.assertFalse(port._filesystem.isdir(last_tmpdir)) + + def test_two_starts_cleans_up_properly(self): + port = TestWebKitPort() + driver = Driver(port, 0, pixel_tests=True) + driver._server_process_constructor = MockServerProcess + driver.start(True, []) + last_tmpdir = port._filesystem.last_tmpdir + driver._start(True, []) + self.assertFalse(port._filesystem.isdir(last_tmpdir)) + + def test_start_actually_starts(self): + port = TestWebKitPort() + driver = Driver(port, 0, pixel_tests=True) + driver._server_process_constructor = MockServerProcess + driver.start(True, []) + self.assertTrue(driver._server_process.started) + + +class MockServerProcess(object): + def __init__(self, port_obj=None, name=None, cmd=None, env=None, universal_newlines=False, lines=None): + self.timed_out = False + self.lines = lines or [] + self.crashed = False + self.started = False + + def has_crashed(self): + return self.crashed + + def read_stdout_line(self, deadline): + return self.lines.pop(0) + "\n" + + def read_stdout(self, deadline, size): + first_line = self.lines[0] + if size > len(first_line): + self.lines.pop(0) + remaining_size = size - len(first_line) - 1 + if not remaining_size: + return first_line + "\n" + return first_line + "\n" + self.read_stdout(deadline, remaining_size) + result = self.lines[0][:size] + self.lines[0] = self.lines[0][size:] + return result + + def read_either_stdout_or_stderr_line(self, deadline): + # FIXME: We should have tests which intermix stderr and stdout lines. + return self.read_stdout_line(deadline), None + + def start(self): + self.started = True + + def stop(self, kill_directly=False): + return + + def kill(self): + return + if __name__ == '__main__': unittest.main() diff --git a/Tools/Scripts/webkitpy/layout_tests/port/gtk.py b/Tools/Scripts/webkitpy/layout_tests/port/gtk.py index 6c59427f3..ebb761bbd 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/gtk.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/gtk.py @@ -33,7 +33,7 @@ import subprocess from webkitpy.layout_tests.models.test_configuration import TestConfiguration from webkitpy.layout_tests.port.server_process import ServerProcess -from webkitpy.layout_tests.port.webkit import WebKitDriver, WebKitPort +from webkitpy.layout_tests.port.webkit import WebKitPort from webkitpy.layout_tests.port.pulseaudio_sanitizer import PulseAudioSanitizer from webkitpy.layout_tests.port.xvfbdriver import XvfbDriver from webkitpy.common.system.executive import Executive diff --git a/Tools/Scripts/webkitpy/layout_tests/port/qt.py b/Tools/Scripts/webkitpy/layout_tests/port/qt.py index 154cfdab8..aaaafac5d 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/qt.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/qt.py @@ -28,6 +28,7 @@ """QtWebKit implementation of the Port interface.""" +import glob import logging import re import sys @@ -93,6 +94,15 @@ class QtPort(WebKitPort): else: return self._build_path('lib/libQtWebKit.so') + def _modules_to_search_for_symbols(self): + # We search in every library to be reliable in the case of building with CONFIG+=force_static_libs_as_shared. + if self.operating_system() == 'mac': + frameworks = glob.glob(os.path.join(self._build_path('lib'), '*.framework')) + return [os.path.join(framework, os.path.splitext(os.path.basename(framework))[0]) for framework in frameworks] + else: + suffix = 'dll' if self.operating_system() == 'win' else 'so' + return glob.glob(os.path.join(self._build_path('lib'), 'lib*.' + suffix)) + @memoized def qt_version(self): version = '' diff --git a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py index d376e774a..d5b7c0d7f 100755 --- 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.""" -import base64 import itertools import logging import operator import re -import sys import time -from webkitpy.common.memoized import memoized -from webkitpy.common.net.buildbot import BuildBot -from webkitpy.common.system.environment import Environment from webkitpy.common.system.executive import Executive, ScriptError -from webkitpy.common.system.path import cygpath -from webkitpy.layout_tests.port import builders, server_process, Port, Driver, DriverOutput +from webkitpy.layout_tests.port import server_process, Port _log = logging.getLogger(__name__) @@ -52,22 +46,8 @@ _log = logging.getLogger(__name__) class WebKitPort(Port): - def driver_name(self): - if self.get_option('webkit_test_runner'): - return "WebKitTestRunner" - return "DumpRenderTree" - # FIXME: Eventually we should standarize port naming, and make this method smart enough # to use for all port configurations (including architectures, graphics types, etc). - def baseline_search_path(self): - search_paths = [] - if self.get_option('webkit_test_runner'): - search_paths.append(self._wk2_port_name()) - search_paths.append(self.name()) - if self.name() != self.port_name: - search_paths.append(self.port_name) - return map(self._webkit_baseline_path, search_paths) - def _port_flag_for_scripts(self): # This is overrriden by ports which need a flag passed to scripts to distinguish the use of that port. # For example --qt on linux, since a user might have both Gtk and Qt libraries installed. @@ -116,37 +96,6 @@ class WebKitPort(Port): def _build_driver_flags(self): return [] - def _check_driver(self): - driver_path = self._path_to_driver() - if not self._filesystem.exists(driver_path): - _log.error("%s was not found at %s" % (self.driver_name(), driver_path)) - return False - return True - - def check_build(self, needs_http): - # If we're using a pre-built copy of WebKit (--root), we assume it also includes a build of DRT. - if not self.get_option('root') and self.get_option('build') and not self._build_driver(): - return False - if not self._check_driver(): - return False - if self.get_option('pixel_tests'): - if not self.check_image_diff(): - return False - if not self._check_port_build(): - return False - return True - - def _check_port_build(self): - # Ports can override this method to do additional checks. - return True - - def check_image_diff(self, override_step=None, logging=True): - image_diff_path = self._path_to_image_diff() - if not self._filesystem.exists(image_diff_path): - _log.error("ImageDiff was not found at %s" % image_diff_path) - return False - return True - def diff_image(self, expected_contents, actual_contents, tolerance=None): # Handle the case where the test didn't actually generate an image. # FIXME: need unit tests for this. @@ -222,19 +171,6 @@ class WebKitPort(Port): return (output_image, diff_percent) - def setup_environ_for_server(self, server_name=None): - clean_env = super(WebKitPort, self).setup_environ_for_server(server_name) - self._copy_value_from_environ_if_set(clean_env, 'WEBKIT_TESTFONTS') - return clean_env - - def default_results_directory(self): - # Results are store relative to the built products to make it easy - # to have multiple copies of webkit checked out and built. - return self._build_path('layout-test-results') - - def _driver_class(self): - return WebKitDriver - def _tests_for_other_platforms(self): # By default we will skip any directory under LayoutTests/platform # that isn't in our baseline search path (this mirrors what @@ -360,334 +296,3 @@ class WebKitPort(Port): tests_to_skip.update(self._tests_for_other_platforms()) tests_to_skip.update(self._skipped_tests_for_unsupported_features(test_list)) return tests_to_skip - - def _build_path(self, *comps): - # --root is used for running with a pre-built root (like from a nightly zip). - build_directory = self.get_option('root') or self.get_option('build_directory') - if not build_directory: - build_directory = self._config.build_directory(self.get_option('configuration')) - # Set --build-directory here Since this modifies the options object used by the worker subprocesses, - # it avoids the slow call out to build_directory in each subprocess. - self.set_option_default('build_directory', build_directory) - return self._filesystem.join(self._filesystem.abspath(build_directory), *comps) - - def _path_to_driver(self): - return self._build_path(self.driver_name()) - - def _path_to_webcore_library(self): - return None - - def _path_to_helper(self): - return None - - def _path_to_image_diff(self): - return self._build_path('ImageDiff') - - def _path_to_wdiff(self): - # FIXME: This does not exist on a default Mac OS X Leopard install. - return 'wdiff' - - # FIXME: This does not belong on the port object. - @memoized - def _path_to_apache(self): - # The Apache binary path can vary depending on OS and distribution - # See http://wiki.apache.org/httpd/DistrosDefaultLayout - for path in ["/usr/sbin/httpd", "/usr/sbin/apache2"]: - if self._filesystem.exists(path): - return path - _log.error("Could not find apache. Not installed or unknown path.") - return None - - # FIXME: This belongs on some platform abstraction instead of Port. - def _is_redhat_based(self): - return self._filesystem.exists('/etc/redhat-release') - - def _is_debian_based(self): - return self._filesystem.exists('/etc/debian_version') - - # We pass sys_platform into this method to make it easy to unit test. - def _apache_config_file_name_for_platform(self, sys_platform): - if sys_platform == 'cygwin': - return 'cygwin-httpd.conf' # CYGWIN is the only platform to still use Apache 1.3. - if sys_platform.startswith('linux'): - if self._is_redhat_based(): - return 'fedora-httpd.conf' # This is an Apache 2.x config file despite the naming. - if self._is_debian_based(): - return 'apache2-debian-httpd.conf' - # All platforms use apache2 except for CYGWIN (and Mac OS X Tiger and prior, which we no longer support). - return "apache2-httpd.conf" - - def _path_to_apache_config_file(self): - config_file_name = self._apache_config_file_name_for_platform(sys.platform) - return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', config_file_name) - - -class WebKitDriver(Driver): - """WebKit implementation of the DumpRenderTree/WebKitTestRunner interface.""" - - def __init__(self, port, worker_number, pixel_tests, no_timeout=False): - Driver.__init__(self, port, worker_number, pixel_tests, no_timeout) - self._driver_tempdir = None - # WebKitTestRunner can report back subprocess crashes by printing - # "#CRASHED - PROCESSNAME". Since those can happen at any time - # and ServerProcess won't be aware of them (since the actual tool - # didn't crash, just a subprocess) we record the crashed subprocess name here. - self._crashed_process_name = None - self._crashed_pid = None - - # WebKitTestRunner can report back subprocesses that became unresponsive - # This could mean they crashed. - self._subprocess_was_unresponsive = False - - # stderr reading is scoped on a per-test (not per-block) basis, so we store the accumulated - # stderr output, as well as if we've seen #EOF on this driver instance. - # FIXME: We should probably remove _read_first_block and _read_optional_image_block and - # instead scope these locally in run_test. - self.error_from_test = str() - self.err_seen_eof = False - self._server_process = None - - def __del__(self): - self.stop() - - def cmd_line(self, pixel_tests, per_test_args): - cmd = self._command_wrapper(self._port.get_option('wrapper')) - cmd.append(self._port._path_to_driver()) - if self._port.get_option('gc_between_tests'): - cmd.append('--gc-between-tests') - if self._port.get_option('complex_text'): - cmd.append('--complex-text') - if self._port.get_option('threaded'): - cmd.append('--threaded') - if self._no_timeout: - cmd.append('--no-timeout') - # FIXME: We need to pass --timeout=SECONDS to WebKitTestRunner for WebKit2. - - cmd.extend(self._port.get_option('additional_drt_flag', [])) - - if pixel_tests: - cmd.append('--pixel-tests') - cmd.extend(per_test_args) - - cmd.append('-') - return cmd - - def _start(self, pixel_tests, per_test_args): - self.stop() - self._driver_tempdir = self._port._filesystem.mkdtemp(prefix='%s-' % self._port.driver_name()) - server_name = self._port.driver_name() - environment = self._port.setup_environ_for_server(server_name) - environment['DYLD_LIBRARY_PATH'] = self._port._build_path() - environment['DYLD_FRAMEWORK_PATH'] = self._port._build_path() - # FIXME: We're assuming that WebKitTestRunner checks this DumpRenderTree-named environment variable. - environment['DUMPRENDERTREE_TEMP'] = str(self._driver_tempdir) - environment['LOCAL_RESOURCE_ROOT'] = self._port.layout_tests_dir() - self._crashed_process_name = None - self._crashed_pid = None - self._server_process = server_process.ServerProcess(self._port, server_name, self.cmd_line(pixel_tests, per_test_args), environment) - - def has_crashed(self): - if self._server_process is None: - return False - if self._crashed_process_name: - return True - if self._server_process.has_crashed(): - self._crashed_process_name = self._server_process.name() - self._crashed_pid = self._server_process.pid() - return True - return False - - def _check_for_driver_crash(self, error_line): - if error_line == "#CRASHED\n": - # This is used on Windows to report that the process has crashed - # See http://trac.webkit.org/changeset/65537. - self._crashed_process_name = self._server_process.name() - self._crashed_pid = self._server_process.pid() - elif (error_line.startswith("#CRASHED - WebProcess") - or error_line.startswith("#PROCESS UNRESPONSIVE - WebProcess")): - # WebKitTestRunner uses this to report that the WebProcess subprocess crashed. - pid = None - m = re.search('pid (\d+)', error_line) - if m: - pid = int(m.group(1)) - self._crashed_process_name = 'WebProcess' - self._crashed_pid = pid - # FIXME: delete this after we're sure this code is working :) - _log.debug('WebProcess crash, pid = %s, error_line = %s' % (str(pid), error_line)) - if error_line.startswith("#PROCESS UNRESPONSIVE - WebProcess"): - self._subprocess_was_unresponsive = True - return True - return self.has_crashed() - - def _command_from_driver_input(self, driver_input): - # FIXME: performance tests pass in full URLs instead of test names. - if driver_input.test_name.startswith('http://') or driver_input.test_name.startswith('https://') or driver_input.test_name == ('about:blank'): - command = driver_input.test_name - elif self.is_http_test(driver_input.test_name): - command = self.test_to_uri(driver_input.test_name) - else: - command = self._port.abspath_for_test(driver_input.test_name) - if sys.platform == 'cygwin': - command = cygpath(command) - - if driver_input.image_hash: - # "'" is the separator of command fields. - command += "'" + driver_input.image_hash - return command + "\n" - - def _read_first_block(self, deadline): - # returns (text_content, audio_content) - block = self._read_block(deadline) - if block.content_type == 'audio/wav': - return (None, block.decoded_content) - return (block.decoded_content, None) - - def _read_optional_image_block(self, deadline): - # returns (image, actual_image_hash) - block = self._read_block(deadline, wait_for_stderr_eof=True) - if block.content and block.content_type == 'image/png': - return (block.decoded_content, block.content_hash) - return (None, block.content_hash) - - def run_test(self, driver_input): - start_time = time.time() - self.start(driver_input.should_run_pixel_test, driver_input.args) - test_begin_time = time.time() - self.error_from_test = str() - self.err_seen_eof = False - - command = self._command_from_driver_input(driver_input) - deadline = test_begin_time + int(driver_input.timeout) / 1000.0 - - self._server_process.write(command) - text, audio = self._read_first_block(deadline) # First block is either text or audio - image, actual_image_hash = self._read_optional_image_block(deadline) # The second (optional) block is image data. - - # We may not have read all of the output if an error (crash) occured. - # Since some platforms output the stacktrace over error, we should - # dump any buffered error into self.error_from_test. - # FIXME: We may need to also read stderr until the process dies? - self.error_from_test += self._server_process.pop_all_buffered_stderr() - - crash_log = None - if self.has_crashed(): - crash_log = self._port._get_crash_log(self._crashed_process_name, self._crashed_pid, text, self.error_from_test, - newer_than=start_time) - - # If we don't find a crash log use a placeholder error message instead. - if not crash_log: - crash_log = 'no crash log found for %s:%d.' % (self._crashed_process_name, self._crashed_pid) - # If we were unresponsive append a message informing there may not have been a crash. - if self._subprocess_was_unresponsive: - crash_log += ' Process failed to become responsive before timing out.' - - timeout = self._server_process.timed_out - if timeout: - # DRT doesn't have a built in timer to abort the test, so we might as well - # kill the process directly and not wait for it to shut down cleanly (since it may not). - self._server_process.kill() - - return DriverOutput(text, image, actual_image_hash, audio, - crash=self.has_crashed(), test_time=time.time() - test_begin_time, - timeout=timeout, error=self.error_from_test, - crashed_process_name=self._crashed_process_name, - crashed_pid=self._crashed_pid, crash_log=crash_log) - - def _read_header(self, block, line, header_text, header_attr, header_filter=None): - if line.startswith(header_text) and getattr(block, header_attr) is None: - value = line.split()[1] - if header_filter: - value = header_filter(value) - setattr(block, header_attr, value) - return True - return False - - def _process_stdout_line(self, block, line): - if (self._read_header(block, line, 'Content-Type: ', 'content_type') - or self._read_header(block, line, 'Content-Transfer-Encoding: ', 'encoding') - or self._read_header(block, line, 'Content-Length: ', '_content_length', int) - or self._read_header(block, line, 'ActualHash: ', 'content_hash')): - return - # Note, we're not reading ExpectedHash: here, but we could. - # If the line wasn't a header, we just append it to the content. - block.content += line - - def _strip_eof(self, line): - if line and line.endswith("#EOF\n"): - return line[:-5], True - return line, False - - def _read_block(self, deadline, wait_for_stderr_eof=False): - block = ContentBlock() - out_seen_eof = False - - while not self.has_crashed(): - if out_seen_eof and (self.err_seen_eof or not wait_for_stderr_eof): - break - - if self.err_seen_eof: - out_line = self._server_process.read_stdout_line(deadline) - err_line = None - elif out_seen_eof: - out_line = None - err_line = self._server_process.read_stderr_line(deadline) - else: - out_line, err_line = self._server_process.read_either_stdout_or_stderr_line(deadline) - - if self._server_process.timed_out or self.has_crashed(): - break - - if out_line: - assert not out_seen_eof - out_line, out_seen_eof = self._strip_eof(out_line) - if err_line: - assert not self.err_seen_eof - err_line, self.err_seen_eof = self._strip_eof(err_line) - - if out_line: - if out_line[-1] != "\n": - _log.error("Last character read from DRT stdout line was not a newline! This indicates either a NRWT or DRT bug.") - content_length_before_header_check = block._content_length - self._process_stdout_line(block, out_line) - # FIXME: Unlike HTTP, DRT dumps the content right after printing a Content-Length header. - # Don't wait until we're done with headers, just read the binary blob right now. - if content_length_before_header_check != block._content_length: - block.content = self._server_process.read_stdout(deadline, block._content_length) - - if err_line: - if self._check_for_driver_crash(err_line): - break - self.error_from_test += err_line - - block.decode_content() - return block - - def start(self, pixel_tests, per_test_args): - if not self._server_process: - self._start(pixel_tests, per_test_args) - - def stop(self): - if self._server_process: - self._server_process.stop() - self._server_process = None - - if self._driver_tempdir: - self._port._filesystem.rmtree(str(self._driver_tempdir)) - self._driver_tempdir = None - - -class ContentBlock(object): - def __init__(self): - self.content_type = None - self.encoding = None - self.content_hash = None - self._content_length = None - # Content is treated as binary data even though the text output is usually UTF-8. - self.content = str() # FIXME: Should be bytearray() once we require Python 2.6. - self.decoded_content = None - - def decode_content(self): - if self.encoding == 'base64': - self.decoded_content = base64.b64decode(self.content) - else: - self.decoded_content = self.content diff --git a/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py index 54ad31919..078182541 100755 --- a/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py @@ -34,7 +34,7 @@ from webkitpy.common.system.outputcapture import OutputCapture from webkitpy.common.system.systemhost_mock import MockSystemHost from webkitpy.layout_tests.models.test_configuration import TestConfiguration from webkitpy.layout_tests.port import port_testcase -from webkitpy.layout_tests.port.webkit import WebKitPort, WebKitDriver +from webkitpy.layout_tests.port.webkit import WebKitPort from webkitpy.layout_tests.port.config_mock import MockConfig from webkitpy.tool.mocktool import MockOptions @@ -231,182 +231,3 @@ class WebKitPortTest(port_testcase.PortTestCase): # Mock out _apache_config_file_name_for_platform to ignore the passed sys.platform value. port._apache_config_file_name_for_platform = lambda platform: 'httpd.conf' self.assertEquals(port._path_to_apache_config_file(), '/mock-checkout/LayoutTests/http/conf/httpd.conf') - - -class MockServerProcess(object): - def __init__(self, lines=None): - self.timed_out = False - self.lines = lines or [] - self.crashed = False - - def has_crashed(self): - return self.crashed - - def read_stdout_line(self, deadline): - return self.lines.pop(0) + "\n" - - def read_stdout(self, deadline, size): - first_line = self.lines[0] - if size > len(first_line): - self.lines.pop(0) - remaining_size = size - len(first_line) - 1 - if not remaining_size: - return first_line + "\n" - return first_line + "\n" + self.read_stdout(deadline, remaining_size) - result = self.lines[0][:size] - self.lines[0] = self.lines[0][size:] - return result - - def read_either_stdout_or_stderr_line(self, deadline): - # FIXME: We should have tests which intermix stderr and stdout lines. - return self.read_stdout_line(deadline), None - - def start(self): - return - - def stop(self, kill_directly=False): - return - - def kill(self): - return - - -class WebKitDriverTest(unittest.TestCase): - def test_read_block(self): - port = TestWebKitPort() - driver = WebKitDriver(port, 0, pixel_tests=False) - driver._server_process = MockServerProcess([ - 'ActualHash: foobar', - 'Content-Type: my_type', - 'Content-Transfer-Encoding: none', - "#EOF", - ]) - content_block = driver._read_block(0) - self.assertEquals(content_block.content_type, 'my_type') - self.assertEquals(content_block.encoding, 'none') - self.assertEquals(content_block.content_hash, 'foobar') - driver._server_process = None - - def test_read_binary_block(self): - port = TestWebKitPort() - driver = WebKitDriver(port, 0, pixel_tests=True) - driver._server_process = MockServerProcess([ - 'ActualHash: actual', - 'ExpectedHash: expected', - 'Content-Type: image/png', - 'Content-Length: 9', - "12345678", - "#EOF", - ]) - content_block = driver._read_block(0) - self.assertEquals(content_block.content_type, 'image/png') - self.assertEquals(content_block.content_hash, 'actual') - self.assertEquals(content_block.content, '12345678\n') - self.assertEquals(content_block.decoded_content, '12345678\n') - driver._server_process = None - - def test_read_base64_block(self): - port = TestWebKitPort() - driver = WebKitDriver(port, 0, pixel_tests=True) - driver._server_process = MockServerProcess([ - 'ActualHash: actual', - 'ExpectedHash: expected', - 'Content-Type: image/png', - 'Content-Transfer-Encoding: base64', - 'Content-Length: 12', - 'MTIzNDU2NzgK#EOF', - ]) - content_block = driver._read_block(0) - self.assertEquals(content_block.content_type, 'image/png') - self.assertEquals(content_block.content_hash, 'actual') - self.assertEquals(content_block.encoding, 'base64') - self.assertEquals(content_block.content, 'MTIzNDU2NzgK') - self.assertEquals(content_block.decoded_content, '12345678\n') - - def test_no_timeout(self): - port = TestWebKitPort() - driver = WebKitDriver(port, 0, pixel_tests=True, no_timeout=True) - self.assertEquals(driver.cmd_line(True, []), ['/mock-build/DumpRenderTree', '--no-timeout', '--pixel-tests', '-']) - - def test_check_for_driver_crash(self): - port = TestWebKitPort() - driver = WebKitDriver(port, 0, pixel_tests=True) - - class FakeServerProcess(object): - def __init__(self, crashed): - self.crashed = crashed - - def pid(self): - return 1234 - - def name(self): - return 'FakeServerProcess' - - def has_crashed(self): - return self.crashed - - def stop(self): - pass - - def assert_crash(driver, error_line, crashed, name, pid, unresponsive=False): - self.assertEquals(driver._check_for_driver_crash(error_line), crashed) - self.assertEquals(driver._crashed_process_name, name) - self.assertEquals(driver._crashed_pid, pid) - self.assertEquals(driver._subprocess_was_unresponsive, unresponsive) - driver.stop() - - driver._server_process = FakeServerProcess(False) - assert_crash(driver, '', False, None, None) - - driver._crashed_process_name = None - driver._crashed_pid = None - driver._server_process = FakeServerProcess(False) - driver._subprocess_was_unresponsive = False - assert_crash(driver, '#CRASHED\n', True, 'FakeServerProcess', 1234) - - driver._crashed_process_name = None - driver._crashed_pid = None - driver._server_process = FakeServerProcess(False) - driver._subprocess_was_unresponsive = False - assert_crash(driver, '#CRASHED - WebProcess\n', True, 'WebProcess', None) - - driver._crashed_process_name = None - driver._crashed_pid = None - driver._server_process = FakeServerProcess(False) - driver._subprocess_was_unresponsive = False - assert_crash(driver, '#CRASHED - WebProcess (pid 8675)\n', True, 'WebProcess', 8675) - - driver._crashed_process_name = None - driver._crashed_pid = None - driver._server_process = FakeServerProcess(False) - driver._subprocess_was_unresponsive = False - assert_crash(driver, '#PROCESS UNRESPONSIVE - WebProcess (pid 8675)\n', True, 'WebProcess', 8675, True) - - driver._crashed_process_name = None - driver._crashed_pid = None - driver._server_process = FakeServerProcess(True) - driver._subprocess_was_unresponsive = False - assert_crash(driver, '', True, 'FakeServerProcess', 1234) - - def test_creating_a_port_does_not_write_to_the_filesystem(self): - port = TestWebKitPort() - driver = WebKitDriver(port, 0, pixel_tests=True) - self.assertEquals(port._filesystem.written_files, {}) - self.assertEquals(port._filesystem.last_tmpdir, None) - - def test_stop_cleans_up_properly(self): - port = TestWebKitPort() - driver = WebKitDriver(port, 0, pixel_tests=True) - driver.start(True, []) - last_tmpdir = port._filesystem.last_tmpdir - self.assertNotEquals(last_tmpdir, None) - driver.stop() - self.assertFalse(port._filesystem.isdir(last_tmpdir)) - - def test_two_starts_cleans_up_properly(self): - port = TestWebKitPort() - driver = WebKitDriver(port, 0, pixel_tests=True) - driver.start(True, []) - last_tmpdir = port._filesystem.last_tmpdir - driver._start(True, []) - self.assertFalse(port._filesystem.isdir(last_tmpdir)) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/xvfbdriver.py b/Tools/Scripts/webkitpy/layout_tests/port/xvfbdriver.py index cfcb5a18c..b20ca98ee 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/xvfbdriver.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/xvfbdriver.py @@ -32,13 +32,13 @@ import signal import subprocess from webkitpy.layout_tests.port.server_process import ServerProcess -from webkitpy.layout_tests.port.webkit import WebKitDriver +from webkitpy.layout_tests.port.driver import Driver from webkitpy.common.system.executive import Executive _log = logging.getLogger(__name__) -class XvfbDriver(WebKitDriver): +class XvfbDriver(Driver): def _start(self, pixel_tests, per_test_args): # Collect the number of X servers running already and make @@ -66,7 +66,7 @@ class XvfbDriver(WebKitDriver): self._server_process = ServerProcess(self._port, server_name, self.cmd_line(pixel_tests, per_test_args), environment) def stop(self): - WebKitDriver.stop(self) + super(XvfbDriver, self).stop() if getattr(self, '_xvfb_process', None): try: self._xvfb_process.terminate() diff --git a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py index 60db587e0..d15166606 100755 --- a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py +++ b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py @@ -425,6 +425,8 @@ def parse_args(args=None): # https://bugs.webkit.org/show_bug.cgi?id=91539. optparse.make_option("--shard-ref-tests", action="store_true", help="Run ref tests in dedicated shard(s). Enabled on Android by default."), + optparse.make_option("--additional-env-var", type="string", action="append", default=[], + help="Passes that environment variable to the tests (--additional-env-var=NAME=VALUE)"), ])) option_group_definitions.append(("Miscellaneous Options", [ diff --git a/Tools/Scripts/webkitpy/performance_tests/perftest.py b/Tools/Scripts/webkitpy/performance_tests/perftest.py index de63f3e8d..8623c0aee 100644 --- a/Tools/Scripts/webkitpy/performance_tests/perftest.py +++ b/Tools/Scripts/webkitpy/performance_tests/perftest.py @@ -99,7 +99,9 @@ class PerfTest(object): # Following are for handle existing test like Dromaeo re.compile(re.escape("""main frame - has 1 onunload handler(s)""")), re.compile(re.escape("""frame "<!--framePath //<!--frame0-->-->" - has 1 onunload handler(s)""")), - re.compile(re.escape("""frame "<!--framePath //<!--frame0-->/<!--frame0-->-->" - has 1 onunload handler(s)"""))] + re.compile(re.escape("""frame "<!--framePath //<!--frame0-->/<!--frame0-->-->" - has 1 onunload handler(s)""")), + # Following is for html5.html + re.compile(re.escape("""Blocked access to external URL http://www.whatwg.org/specs/web-apps/current-work/"""))] _statistics_keys = ['avg', 'median', 'stdev', 'min', 'max'] diff --git a/Tools/Scripts/webkitpy/style/checker.py b/Tools/Scripts/webkitpy/style/checker.py index 8cd8745bf..10f3448ec 100644 --- a/Tools/Scripts/webkitpy/style/checker.py +++ b/Tools/Scripts/webkitpy/style/checker.py @@ -178,8 +178,9 @@ _PATH_RULES_SPECIFIER = [ ["-build/header_guard"]), ([# assembler has lots of opcodes that use underscores, so # we don't check for underscores in that directory. - "/Source/JavaScriptCore/assembler/"], - ["-readability/naming"]), + "Source/JavaScriptCore/assembler/", + "Source/JavaScriptCore/jit/JIT"], + ["-readability/naming/underscores"]), ([# JITStubs has an usual syntax which causes false alarms for a few checks. "JavaScriptCore/jit/JITStubs.cpp"], ["-readability/parameter_name", @@ -219,7 +220,9 @@ _PATH_RULES_SPECIFIER = [ "Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer1.cpp", "Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp", "Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp", - "Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp"], + "Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp", + "Source/WebCore/platform/network/soup/ProxyResolverSoup.cpp", + "Source/WebCore/platform/network/soup/ProxyResolverSoup.h"], ["-readability/naming"]), # For third-party Python code, keep only the following checks-- diff --git a/Tools/Scripts/webkitpy/style/checkers/cpp.py b/Tools/Scripts/webkitpy/style/checkers/cpp.py index ba1153087..78cd88250 100644 --- a/Tools/Scripts/webkitpy/style/checkers/cpp.py +++ b/Tools/Scripts/webkitpy/style/checkers/cpp.py @@ -3137,11 +3137,13 @@ def check_identifier_name_in_declaration(filename, line_number, line, file_state and not modified_identifier.startswith('Eina_') and not modified_identifier.startswith('Evas_') and not modified_identifier.startswith('Ewk_') + and not modified_identifier.startswith('cti_') and not modified_identifier.find('::qt_') >= 0 and not modified_identifier.find('::_q_') >= 0 and not modified_identifier == "const_iterator" - and not modified_identifier == "vm_throw"): - error(line_number, 'readability/naming', 4, identifier + " is incorrectly named. Don't use underscores in your identifier names.") + and not modified_identifier == "vm_throw" + and not modified_identifier == "DFG_OPERATION"): + error(line_number, 'readability/naming/underscores', 4, identifier + " is incorrectly named. Don't use underscores in your identifier names.") # Check for variables named 'l', these are too easy to confuse with '1' in some fonts if modified_identifier == 'l': @@ -3564,6 +3566,7 @@ class CppChecker(object): 'readability/multiline_string', 'readability/parameter_name', 'readability/naming', + 'readability/naming/underscores', 'readability/null', 'readability/pass_ptr', 'readability/streams', diff --git a/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py b/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py index 1675c7010..339897fe8 100644 --- a/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py +++ b/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py @@ -4425,7 +4425,7 @@ class WebKitStyleTest(CppStyleTestBase): 'foo.cpp') def test_names(self): - name_underscore_error_message = " is incorrectly named. Don't use underscores in your identifier names. [readability/naming] [4]" + name_underscore_error_message = " is incorrectly named. Don't use underscores in your identifier names. [readability/naming/underscores] [4]" name_tooshort_error_message = " is incorrectly named. Don't use the single letter 'l' as an identifier name. [readability/naming] [4]" # Basic cases from WebKit style guide. @@ -4569,11 +4569,11 @@ class WebKitStyleTest(CppStyleTestBase): # Test that this doesn't also apply to files not in a 'gtk' directory. self.assert_lint('void webkit_web_view_load(int var1, int var2)', 'webkit_web_view_load is incorrectly named. Don\'t use underscores in your identifier names.' - ' [readability/naming] [4]', 'Source/Webkit/webkit/foo.cpp') + ' [readability/naming/underscores] [4]', 'Source/Webkit/webkit/foo.cpp') # Test that this doesn't also apply to names that don't start with 'webkit_'. self.assert_lint_one_of_many_errors_re('void otherkit_web_view_load(int var1, int var2)', 'otherkit_web_view_load is incorrectly named. Don\'t use underscores in your identifier names.' - ' [readability/naming] [4]', 'Source/Webkit/webkit/foo.cpp') + ' [readability/naming/underscores] [4]', 'Source/Webkit/webkit/foo.cpp') # There is an exception for some unit tests that begin with "tst_". self.assert_lint('void tst_QWebFrame::arrayObjectEnumerable(int var1, int var2)', '') diff --git a/Tools/Scripts/webkitpy/test/main.py b/Tools/Scripts/webkitpy/test/main.py index abb297b2b..2968e7daa 100644 --- a/Tools/Scripts/webkitpy/test/main.py +++ b/Tools/Scripts/webkitpy/test/main.py @@ -24,6 +24,7 @@ """unit testing code for webkitpy.""" import logging +import multiprocessing import optparse import StringIO import sys @@ -63,8 +64,8 @@ class Tester(object): help='do not run the integration tests') parser.add_option('-p', '--pass-through', action='store_true', default=False, help='be debugger friendly by passing captured output through to the system') - parser.add_option('-j', '--child-processes', action='store', type='int', default=1, - help='number of tests to run in parallel') + parser.add_option('-j', '--child-processes', action='store', type='int', default=(1 if sys.platform == 'win32' else multiprocessing.cpu_count()), + help='number of tests to run in parallel (default=%default)') parser.epilog = ('[args...] is an optional list of modules, test_classes, or individual tests. ' 'If no args are given, all the tests will be run.') |