Diff
Modified: trunk/Tools/ChangeLog (243558 => 243559)
--- trunk/Tools/ChangeLog 2019-03-27 19:56:02 UTC (rev 243558)
+++ trunk/Tools/ChangeLog 2019-03-27 20:25:15 UTC (rev 243559)
@@ -1,3 +1,99 @@
+2019-03-27 David Kilzer <ddkil...@apple.com>
+
+ run-webkit-tests should check for leaks in WebKit processes
+ <https://webkit.org/b/193772>
+ <rdar://problem/46526680>
+
+ Reviewed by Ryosuke Niwa.
+
+ This works by doing the following:
+ - Add a "#LIST CHILD PROCESSES" command to WebKitTestRunnner.
+ The list of child processes are returned one per line:
+ process.name: pid
+ - Run the "#LIST CHILD PROCESSES" command just before the
+ "#CHECK FOR WORLD LEAKS" command, and store the list of child
+ processes on the ServerProcess object.
+ - When the `--leaks` switch is handled, run check_for_leaks() on
+ each child process after the main test harness.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (handleControlCommand):
+ - Use strncmp() instead of strcmp().
+ - Add support for handling "#LIST CHILD PROCESSES" command.
+
+ * Scripts/webkitpy/port/base.py:
+ (Port.check_for_leaks):
+ * Scripts/webkitpy/port/darwin.py:
+ (DarwinPort.check_for_leaks):
+ - Rename redundant 'process_pid' argument to 'process_id'.
+
+ * Scripts/webkitpy/port/driver.py:
+ (Driver.do_post_tests_work):
+ - Restructure the logic since "#CHECK FOR WORLD LEAKS" is no
+ longer the only command this sends to WebKitTestRunner.
+ - If the `--leaks` switch is present, send the
+ "#LIST CHILD PROCESSES" to WebKitTestRunner and store the
+ result using Port.set_webkit_processes().
+ (Driver._parse_child_processes_output):
+ - Add helper method to parse list of child process names and
+ process IDs returned from WebKitTestRunner.
+
+ * Scripts/webkitpy/port/ios_device.py:
+ (IOSDevicePort.check_for_leaks):
+ - Rename redundant 'process_pid' argument to 'process_id'.
+
+ * Scripts/webkitpy/port/leakdetector.py:
+ (LeakDetector._parse_leaks_output):
+ - Return early if there is no leaks_output.
+ (LeakDetector.check_for_leaks):
+ - Rename redundant 'process_pid' argument to 'process_id'.
+
+ * Scripts/webkitpy/port/server_process.py:
+ (ServerProcess.__init__):
+ (ServerProcess.child_processes):
+ (ServerProcess.set_child_processes):
+ - Add instance variable to Port to store list of child process
+ names and process IDs returned from WebKitTestRunner.
+ (ServerProcess._start):
+ - Clear self._child_processes.
+ (ServerProcess.stop):
+ - If self._child_processes is set, call
+ self._port.check_for_leaks() for each child process.
+
+ * Scripts/webkitpy/port/server_process_unittest.py:
+ (TrivialMockPort.check_for_leaks):
+ - Rename redundant 'process_pid' argument to 'process_id'.
+
+ * Scripts/webkitpy/port/simulator_process.py:
+ (SimulatorProcess.stop):
+ - If self._child_processes is set, call
+ self._port.check_for_leaks() for each child process.
+
+ * Scripts/webkitpy/port/watch_device.py:
+ (WatchDevicePort.check_for_leaks):
+ - Rename redundant 'process_pid' argument to 'process_id'.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::dumpResponse):
+ - Extract method from findAndDumpWorldLeaks() so that it may be
+ reused by findAndDumpWebKitProcessIdentifiers().
+ (WTR::TestController::findAndDumpWebKitProcessIdentifiers):
+ - Add method to output process name and process ID of both the
+ WebContent and Networking processes.
+ (WTR::TestController::findAndDumpWorldLeaks):
+ - Fix missing newline in output when there were no abandoned
+ documents.
+ - Call dumpResponse() for extracted code.
+ (WTR::TestController::handleControlCommand):
+ - Restructure the logic for "#CHECK FOR WORLD LEAKS".
+ - Use strncmp() instead of strcmp().
+ - Call findAndDumpWebKitProcessIdentifiers() when
+ "#LIST CHILD PROCESSES" command is sent.
+ * WebKitTestRunner/TestController.h:
+ (WTR::TestController::dumpResponse):
+ (WTR::TestController::findAndDumpWebKitProcessIdentifiers):
+ - Declare methods.
+
2019-03-27 Carlos Garcia Campos <cgar...@igalia.com>
Unreviewed. Add GLib API test cases after r243434.
Modified: trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm (243558 => 243559)
--- trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm 2019-03-27 19:56:02 UTC (rev 243558)
+++ trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm 2019-03-27 20:25:15 UTC (rev 243559)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2005-2019 Apple Inc. All rights reserved.
* (C) 2007 Graham Dennis (graham.den...@gmail.com)
*
* Redistribution and use in source and binary forms, with or without
@@ -1167,12 +1167,13 @@
static bool handleControlCommand(const char* command)
{
- if (!strcmp("#CHECK FOR WORLD LEAKS", command)) {
- // DumpRenderTree does not support checking for world leaks.
+ if (!strncmp("#CHECK FOR WORLD LEAKS", command, 22) || !strncmp("#LIST CHILD PROCESSES", command, 21)) {
+ // DumpRenderTree does not support checking for world leaks or listing child processes.
WTF::String result("\n");
+ unsigned resultLength = result.length();
printf("Content-Type: text/plain\n");
- printf("Content-Length: %u\n", result.length());
- fwrite(result.utf8().data(), 1, result.length(), stdout);
+ printf("Content-Length: %u\n", resultLength);
+ fwrite(result.utf8().data(), 1, resultLength, stdout);
printf("#EOF\n");
fprintf(stderr, "#EOF\n");
fflush(stdout);
Modified: trunk/Tools/Scripts/webkitpy/port/base.py (243558 => 243559)
--- trunk/Tools/Scripts/webkitpy/port/base.py 2019-03-27 19:56:02 UTC (rev 243558)
+++ trunk/Tools/Scripts/webkitpy/port/base.py 2019-03-27 20:25:15 UTC (rev 243559)
@@ -1,5 +1,5 @@
# Copyright (C) 2010 Google Inc. All rights reserved.
-# Copyright (C) 2013 Apple Inc. All rights reserved.
+# Copyright (C) 2013-2019 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -371,7 +371,7 @@
result += '\n\ No newline at end of file\n'
return result
- def check_for_leaks(self, process_name, process_pid):
+ def check_for_leaks(self, process_name, process_id):
# Subclasses should check for leaks in the running process
# and print any necessary warnings if leaks are found.
# FIXME: We should consider moving much of this logic into
Modified: trunk/Tools/Scripts/webkitpy/port/darwin.py (243558 => 243559)
--- trunk/Tools/Scripts/webkitpy/port/darwin.py 2019-03-27 19:56:02 UTC (rev 243558)
+++ trunk/Tools/Scripts/webkitpy/port/darwin.py 2019-03-27 20:25:15 UTC (rev 243559)
@@ -1,4 +1,4 @@
-# Copyright (C) 2014-2016 Apple Inc. All rights reserved.
+# Copyright (C) 2014-2019 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -56,11 +56,12 @@
def _port_specific_expectations_files(self, device_type=None):
return list(reversed([self._filesystem.join(self._webkit_baseline_path(p), 'TestExpectations') for p in self.baseline_search_path(device_type=device_type)]))
- def check_for_leaks(self, process_name, process_pid):
+ def check_for_leaks(self, process_name, process_id):
if not self.get_option('leaks'):
return
+
# We could use http://code.google.com/p/psutil/ to get the process_name from the pid.
- self._leak_detector.check_for_leaks(process_name, process_pid)
+ self._leak_detector.check_for_leaks(process_name, process_id)
def print_leaks_summary(self):
if not self.get_option('leaks'):
Modified: trunk/Tools/Scripts/webkitpy/port/driver.py (243558 => 243559)
--- trunk/Tools/Scripts/webkitpy/port/driver.py 2019-03-27 19:56:02 UTC (rev 243558)
+++ trunk/Tools/Scripts/webkitpy/port/driver.py 2019-03-27 20:25:15 UTC (rev 243559)
@@ -1,5 +1,5 @@
# Copyright (C) 2011 Google Inc. All rights reserved.
-# Copyright (c) 2015, 2016 Apple Inc. All rights reserved.
+# Copyright (c) 2015-2019 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -251,21 +251,41 @@
crashed_pid=self._crashed_pid, crash_log=crash_log, pid=pid)
def do_post_tests_work(self):
- if not self._port.get_option('world_leaks'):
- return None
-
if not self._server_process:
return None
- _log.debug('Checking for world leaks...')
- self._server_process.write('#CHECK FOR WORLD LEAKS\n')
- deadline = time.time() + 20
- block = self._read_block(deadline, '', wait_for_stderr_eof=True)
+ if self._port.get_option('leaks'):
+ _log.debug('Gathering child processes...')
+ self._server_process.write('#LIST CHILD PROCESSES\n')
+ deadline = time.time() + 20
+ block = self._read_block(deadline, '', wait_for_stderr_eof=True)
+ self._server_process.set_child_processes(self._parse_child_processes_output(block.decoded_content))
- _log.debug('World leak result: %s' % (block.decoded_content))
+ if self._port.get_option('world_leaks'):
+ _log.debug('Checking for world leaks...')
+ self._server_process.write('#CHECK FOR WORLD LEAKS\n')
+ deadline = time.time() + 20
+ block = self._read_block(deadline, '', wait_for_stderr_eof=True)
- return self._parse_world_leaks_output(block.decoded_content)
+ _log.debug('World leak result: %s' % (block.decoded_content))
+ return self._parse_world_leaks_output(block.decoded_content)
+
+ return None
+
+ @staticmethod
+ def _parse_child_processes_output(output):
+ child_processes = defaultdict(list)
+
+ for line in output.splitlines():
+ m = re.match('^([^:]+): ([0-9]+)$', line)
+ if m:
+ process_name = m.group(1)
+ process_id = m.group(2)
+ child_processes[process_name].append(process_id)
+
+ return child_processes
+
def _parse_world_leaks_output(self, output):
tests_with_world_leaks = defaultdict(list)
Modified: trunk/Tools/Scripts/webkitpy/port/ios_device.py (243558 => 243559)
--- trunk/Tools/Scripts/webkitpy/port/ios_device.py 2019-03-27 19:56:02 UTC (rev 243558)
+++ trunk/Tools/Scripts/webkitpy/port/ios_device.py 2019-03-27 20:25:15 UTC (rev 243559)
@@ -1,4 +1,4 @@
-# Copyright (C) 2014-2018 Apple Inc. All rights reserved.
+# Copyright (C) 2014-2019 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -103,7 +103,7 @@
return version
# FIXME: These need device implementations <rdar://problem/30497991>.
- def check_for_leaks(self, process_name, process_pid):
+ def check_for_leaks(self, process_name, process_id):
pass
def operating_system(self):
Modified: trunk/Tools/Scripts/webkitpy/port/leakdetector.py (243558 => 243559)
--- trunk/Tools/Scripts/webkitpy/port/leakdetector.py 2019-03-27 19:56:02 UTC (rev 243558)
+++ trunk/Tools/Scripts/webkitpy/port/leakdetector.py 2019-03-27 20:25:15 UTC (rev 243559)
@@ -1,4 +1,5 @@
# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2011-2019 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -75,6 +76,8 @@
return leaks_args
def _parse_leaks_output(self, leaks_output):
+ if not leaks_output:
+ return 0, 0, 0
_, count, bytes = re.search(r'Process (?P<pid>\d+): (?P<count>\d+) leaks? for (?P<bytes>\d+) total', leaks_output).groups()
excluded_match = re.search(r'(?P<excluded>\d+) leaks? excluded', leaks_output)
excluded = excluded_match.group('excluded') if excluded_match else 0
@@ -116,15 +119,15 @@
total_leaks += count
return total_leaks
- def check_for_leaks(self, process_name, process_pid):
+ def check_for_leaks(self, process_name, process_id):
_log.debug("Checking for leaks in %s" % process_name)
try:
- leaks_filename = self.leaks_file_name(process_name, process_pid)
+ leaks_filename = self.leaks_file_name(process_name, process_id)
leaks_output_path = self._filesystem.join(self._port.results_directory(), leaks_filename)
# Oddly enough, run-leaks (or the underlying leaks tool) does not seem to always output utf-8,
# thus we pass decode_output=False. Without this code we've seen errors like:
# "UnicodeDecodeError: 'utf8' codec can't decode byte 0x88 in position 779874: unexpected code byte"
- self._port._run_script("run-leaks", self._leaks_args(process_name, process_pid), include_configuration_arguments=False, decode_output=False)
+ self._port._run_script("run-leaks", self._leaks_args(process_name, process_id), include_configuration_arguments=False, decode_output=False)
leaks_output = self._filesystem.read_binary_file(leaks_output_path)
except ScriptError as e:
_log.warn("Failed to run leaks tool: %s" % e.message_with_output())
Modified: trunk/Tools/Scripts/webkitpy/port/server_process.py (243558 => 243559)
--- trunk/Tools/Scripts/webkitpy/port/server_process.py 2019-03-27 19:56:02 UTC (rev 243558)
+++ trunk/Tools/Scripts/webkitpy/port/server_process.py 2019-03-27 20:25:15 UTC (rev 243559)
@@ -1,4 +1,4 @@
-# Copyright (C) 2017 Apple Inc. All rights reserved.
+# Copyright (C) 2017-2019 Apple Inc. All rights reserved.
# Copyright (C) 2010 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -77,6 +77,7 @@
self._treat_no_data_as_crash = treat_no_data_as_crash
self._target_host = target_host or port_obj.host
self._pid = None
+ self._child_processes = {}
self._reset()
# See comment in imports for why we need the win32 APIs and can't just use select.
@@ -83,6 +84,12 @@
# FIXME: there should be a way to get win32 vs. cygwin from platforminfo.
self._use_win32_apis = sys.platform.startswith('win')
+ def child_processes(self):
+ return self._child_processes
+
+ def set_child_processes(self, child_processes):
+ self._child_processes = child_processes
+
def pid(self):
return self._pid
@@ -123,6 +130,7 @@
env=self._env,
universal_newlines=self._universal_newlines)
self._pid = self._proc.pid
+ self._child_processes = {}
if not self._use_win32_apis:
self._set_file_nonblocking(self._proc.stdout)
self._set_file_nonblocking(self._proc.stderr)
@@ -364,6 +372,9 @@
# Only bother to check for leaks or stderr if the process is still running.
if self.poll() is None:
self._port.check_for_leaks(self.process_name(), self.pid())
+ for child_process_name in self._child_processes.keys():
+ for child_process_id in self._child_processes[child_process_name]:
+ self._port.check_for_leaks(child_process_name, child_process_id)
if self._proc.stdin:
self._proc.stdin.close()
Modified: trunk/Tools/Scripts/webkitpy/port/server_process_unittest.py (243558 => 243559)
--- trunk/Tools/Scripts/webkitpy/port/server_process_unittest.py 2019-03-27 19:56:02 UTC (rev 243558)
+++ trunk/Tools/Scripts/webkitpy/port/server_process_unittest.py 2019-03-27 20:25:15 UTC (rev 243559)
@@ -1,4 +1,5 @@
# Copyright (C) 2011 Google Inc. All rights reserved.
+# Copyright (C) 2011-2019 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -46,7 +47,7 @@
def results_directory(self):
return "/mock-results"
- def check_for_leaks(self, process_name, process_pid):
+ def check_for_leaks(self, process_name, process_id):
pass
def process_kill_time(self):
Modified: trunk/Tools/Scripts/webkitpy/port/simulator_process.py (243558 => 243559)
--- trunk/Tools/Scripts/webkitpy/port/simulator_process.py 2019-03-27 19:56:02 UTC (rev 243558)
+++ trunk/Tools/Scripts/webkitpy/port/simulator_process.py 2019-03-27 20:25:15 UTC (rev 243559)
@@ -120,6 +120,9 @@
# Only bother to check for leaks or stderr if the process is still running.
if self.poll() is None:
self._port.check_for_leaks(self.process_name(), self.pid())
+ for child_process_name in self._child_processes.keys():
+ for child_process_id in self._child_processes[child_process_name]:
+ self._port.check_for_leaks(child_process_name, child_process_id)
if self._proc and self._proc.pid:
self._target_host.executive.kill_process(self._proc.pid)
Modified: trunk/Tools/Scripts/webkitpy/port/watch_device.py (243558 => 243559)
--- trunk/Tools/Scripts/webkitpy/port/watch_device.py 2019-03-27 19:56:02 UTC (rev 243558)
+++ trunk/Tools/Scripts/webkitpy/port/watch_device.py 2019-03-27 20:25:15 UTC (rev 243559)
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 Apple Inc. All rights reserved.
+# Copyright (C) 2018-2019 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -101,7 +101,7 @@
return version
# FIXME: These need device implementations <rdar://problem/30497991>.
- def check_for_leaks(self, process_name, process_pid):
+ def check_for_leaks(self, process_name, process_id):
pass
def operating_system(self):
Modified: trunk/Tools/WebKitTestRunner/TestController.cpp (243558 => 243559)
--- trunk/Tools/WebKitTestRunner/TestController.cpp 2019-03-27 19:56:02 UTC (rev 243558)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp 2019-03-27 20:25:15 UTC (rev 243559)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -1034,6 +1034,41 @@
}, 20_s).run();
}
+void TestController::dumpResponse(const String& result)
+{
+ unsigned resultLength = result.length();
+ printf("Content-Type: text/plain\n");
+ printf("Content-Length: %u\n", resultLength);
+ fwrite(result.utf8().data(), 1, resultLength, stdout);
+ printf("#EOF\n");
+ fprintf(stderr, "#EOF\n");
+ fflush(stdout);
+ fflush(stderr);
+}
+
+void TestController::findAndDumpWebKitProcessIdentifiers()
+{
+ StringBuilder builder;
+
+#if PLATFORM(COCOA)
+ builder.append(TestController::webProcessName());
+ builder.appendLiteral(": ");
+ pid_t webContentPID = WKPageGetProcessIdentifier(TestController::singleton().mainWebView()->page());
+ builder.appendNumber(webContentPID);
+ builder.append('\n');
+
+ builder.append(TestController::networkProcessName());
+ builder.appendLiteral(": ");
+ pid_t networkingPID = WKContextGetNetworkProcessIdentifier(m_context.get());
+ builder.appendNumber(networkingPID);
+ builder.append('\n');
+#else
+ builder.append('\n');
+#endif
+
+ dumpResponse(builder.toString());
+}
+
void TestController::findAndDumpWorldLeaks()
{
if (!m_checkForWorldLeaks)
@@ -1056,16 +1091,9 @@
builder.append('\n');
}
} else
- builder.append("no abandoned documents");
+ builder.append("no abandoned documents\n");
- String result = builder.toString();
- printf("Content-Type: text/plain\n");
- printf("Content-Length: %u\n", result.length());
- fwrite(result.utf8().data(), 1, result.length(), stdout);
- printf("#EOF\n");
- fprintf(stderr, "#EOF\n");
- fflush(stdout);
- fflush(stderr);
+ dumpResponse(builder.toString());
}
void TestController::willDestroyWebView()
@@ -1595,14 +1623,19 @@
bool TestController::handleControlCommand(const char* command)
{
- if (!strcmp("#CHECK FOR WORLD LEAKS", command)) {
- if (!m_checkForWorldLeaks) {
+ if (!strncmp("#CHECK FOR WORLD LEAKS", command, 22)) {
+ if (m_checkForWorldLeaks)
+ findAndDumpWorldLeaks();
+ else
WTFLogAlways("WebKitTestRunner asked to check for world leaks, but was not run with --world-leaks");
- return true;
- }
- findAndDumpWorldLeaks();
return true;
}
+
+ if (!strncmp("#LIST CHILD PROCESSES", command, 21)) {
+ findAndDumpWebKitProcessIdentifiers();
+ return true;
+ }
+
return false;
}
Modified: trunk/Tools/WebKitTestRunner/TestController.h (243558 => 243559)
--- trunk/Tools/WebKitTestRunner/TestController.h 2019-03-27 19:56:02 UTC (rev 243558)
+++ trunk/Tools/WebKitTestRunner/TestController.h 2019-03-27 20:25:15 UTC (rev 243559)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2015-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -354,6 +354,8 @@
void checkForWorldLeaks();
void didReceiveLiveDocumentsList(WKArrayRef);
+ void dumpResponse(const String&);
+ void findAndDumpWebKitProcessIdentifiers();
void findAndDumpWorldLeaks();
void decidePolicyForGeolocationPermissionRequestIfPossible();