- Revision
- 102354
- Author
- [email protected]
- Date
- 2011-12-08 11:16:14 -0800 (Thu, 08 Dec 2011)
Log Message
Make finding crash logs by PID work on Snow Leopard
Crash Reporter on Snow Leopard doesn't set the "app_description" extended attribute that we
were using to check the PID of the crashed process. (Crash Reporter on Lion does.) Now we
read the first line of the crash log and pull the PID out of there.
Fixes <http://webkit.org/b/74094> "webkit-patch crash-log <process> <PID>" doesn't work on
Snow Leopard
Reviewed by Darin Adler.
* Scripts/webkitpy/common/system/crashlogs.py:
(CrashLogs._find_newest_log_darwin): Read the first line of the crash log to get the process
name and PID for the log, rather than checking the Lion-only app_description extended
attribute. We now also reject the log if the process name doesn't match what we expect.
* Scripts/webkitpy/common/system/crashlogs_unittest.py:
(make_mock_crash_report_darwin): Added. Returns a mock crash report given a process name and
PID.
(CrashLogsTest.assertLinesEqual): Added. This is a compatibility shim around
unittest.TestCase.assertMultiLineEqual, which didn't exist before Python 2.7.
(CrashLogsTest.test_find_log_darwin): Made the mock crash reports more believable by using
the new make_mock_crash_report_darwin function. Also added tests for files that can't be
read, files that actually contain a crash log for some other process, and files that are
misformatted.
* Scripts/webkitpy/common/system/filesystem.py: Removed FileSystem.getxattr, which is now
unused.
* Scripts/webkitpy/common/system/filesystem_mock.py:
(MockFileSystem.__init__): Removed xattr support, which is now unused.
(MockFileSystem.open_text_file_for_reading): Changed to actually pass the file's data to
ReadableTextFileObject. This function was completely broken before!
(ReadableBinaryFileObject.__init__): Made the data parameter non-optional to try to prevent
bugs like the above.
(ReadableTextFileObject.__init__): Added. Wraps the data in a StringIO object so we can do
things like readline() and seek().
(ReadableTextFileObject.close):
(ReadableTextFileObject.read):
Added. We override the superclass implementation to account for using a StringIO object.
(ReadableTextFileObject.readline):
(ReadableTextFileObject.seek):
Added. These just call through to StringIO.
* Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py:
(MainTest.test_crash_log):
(MainTest.test_web_process_crash_log):
Changed to use make_mock_crash_report_darwin.
Modified Paths
Diff
Modified: trunk/Tools/ChangeLog (102353 => 102354)
--- trunk/Tools/ChangeLog 2011-12-08 19:12:34 UTC (rev 102353)
+++ trunk/Tools/ChangeLog 2011-12-08 19:16:14 UTC (rev 102354)
@@ -1,3 +1,56 @@
+2011-12-08 Adam Roben <[email protected]>
+
+ Make finding crash logs by PID work on Snow Leopard
+
+ Crash Reporter on Snow Leopard doesn't set the "app_description" extended attribute that we
+ were using to check the PID of the crashed process. (Crash Reporter on Lion does.) Now we
+ read the first line of the crash log and pull the PID out of there.
+
+ Fixes <http://webkit.org/b/74094> "webkit-patch crash-log <process> <PID>" doesn't work on
+ Snow Leopard
+
+ Reviewed by Darin Adler.
+
+ * Scripts/webkitpy/common/system/crashlogs.py:
+ (CrashLogs._find_newest_log_darwin): Read the first line of the crash log to get the process
+ name and PID for the log, rather than checking the Lion-only app_description extended
+ attribute. We now also reject the log if the process name doesn't match what we expect.
+
+ * Scripts/webkitpy/common/system/crashlogs_unittest.py:
+ (make_mock_crash_report_darwin): Added. Returns a mock crash report given a process name and
+ PID.
+ (CrashLogsTest.assertLinesEqual): Added. This is a compatibility shim around
+ unittest.TestCase.assertMultiLineEqual, which didn't exist before Python 2.7.
+ (CrashLogsTest.test_find_log_darwin): Made the mock crash reports more believable by using
+ the new make_mock_crash_report_darwin function. Also added tests for files that can't be
+ read, files that actually contain a crash log for some other process, and files that are
+ misformatted.
+
+ * Scripts/webkitpy/common/system/filesystem.py: Removed FileSystem.getxattr, which is now
+ unused.
+
+ * Scripts/webkitpy/common/system/filesystem_mock.py:
+ (MockFileSystem.__init__): Removed xattr support, which is now unused.
+ (MockFileSystem.open_text_file_for_reading): Changed to actually pass the file's data to
+ ReadableTextFileObject. This function was completely broken before!
+ (ReadableBinaryFileObject.__init__): Made the data parameter non-optional to try to prevent
+ bugs like the above.
+ (ReadableTextFileObject.__init__): Added. Wraps the data in a StringIO object so we can do
+ things like readline() and seek().
+
+ (ReadableTextFileObject.close):
+ (ReadableTextFileObject.read):
+ Added. We override the superclass implementation to account for using a StringIO object.
+
+ (ReadableTextFileObject.readline):
+ (ReadableTextFileObject.seek):
+ Added. These just call through to StringIO.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py:
+ (MainTest.test_crash_log):
+ (MainTest.test_web_process_crash_log):
+ Changed to use make_mock_crash_report_darwin.
+
2011-12-06 Jon Lee <[email protected]>
[WK2] Add permissions support (73960)
Modified: trunk/Tools/Scripts/webkitpy/common/system/crashlogs.py (102353 => 102354)
--- trunk/Tools/Scripts/webkitpy/common/system/crashlogs.py 2011-12-08 19:12:34 UTC (rev 102353)
+++ trunk/Tools/Scripts/webkitpy/common/system/crashlogs.py 2011-12-08 19:16:14 UTC (rev 102354)
@@ -26,6 +26,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.
+from __future__ import with_statement
+
+import os
import re
import sys
@@ -55,13 +58,21 @@
logs = self._filesystem.files_under(log_directory, file_filter=is_crash_log)
if not logs:
return None
+ first_line_regex = re.compile(r'^Process:\s+(?P<process_name>.*) \[(?P<pid>\d+)\]$')
for path in reversed(sorted(logs)):
- if pid is not None:
- try:
- app_description = self._filesystem.getxattr(path, 'app_description')
- if not app_description.startswith('%s[%d] version ' % (process_name, pid)):
+ try:
+ with self._filesystem.open_text_file_for_reading(path) as f:
+ first_line = f.readline()
+
+ match = first_line_regex.match(first_line)
+ if not match:
continue
- except KeyError:
- # The file doesn't have the app_description extended attribute for some reason.
- continue
- return self._filesystem.read_text_file(path)
+ if match.group('process_name') != process_name:
+ continue
+ if pid is not None and int(match.group('pid')) != pid:
+ continue
+
+ f.seek(0, os.SEEK_SET)
+ return f.read()
+ except IOError:
+ continue
Modified: trunk/Tools/Scripts/webkitpy/common/system/crashlogs_unittest.py (102353 => 102354)
--- trunk/Tools/Scripts/webkitpy/common/system/crashlogs_unittest.py 2011-12-08 19:12:34 UTC (rev 102353)
+++ trunk/Tools/Scripts/webkitpy/common/system/crashlogs_unittest.py 2011-12-08 19:16:14 UTC (rev 102354)
@@ -29,28 +29,74 @@
from webkitpy.thirdparty.mock import Mock
+def make_mock_crash_report_darwin(process_name, pid):
+ return """Process: {process_name} [{pid}]
+Path: /Volumes/Data/slave/snowleopard-intel-release-tests/build/WebKitBuild/Release/{process_name}
+Identifier: {process_name}
+Version: ??? (???)
+Code Type: X86-64 (Native)
+Parent Process: Python [2578]
+
+Date/Time: 2011-12-07 13:27:34.816 -0800
+OS Version: Mac OS X 10.6.8 (10K549)
+Report Version: 6
+
+Interval Since Last Report: 1660 sec
+Crashes Since Last Report: 1
+Per-App Crashes Since Last Report: 1
+Anonymous UUID: 507D4EEB-9D70-4E2E-B322-2D2F0ABFEDC0
+
+Exception Type: EXC_BREAKPOINT (SIGTRAP)
+Exception Codes: 0x0000000000000002, 0x0000000000000000
+Crashed Thread: 0
+
+Dyld Error Message:
+ Library not loaded: /Volumes/Data/WebKit-BuildSlave/snowleopard-intel-release/build/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore
+ Referenced from: /Volumes/Data/slave/snowleopard-intel-release/build/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit
+ Reason: image not found
+
+Binary Images:
+ 0x7fff5fc00000 - 0x7fff5fc3be0f dyld 132.1 (???) <29DECB19-0193-2575-D838-CF743F0400B2> /usr/lib/dyld
+
+System Profile:
+Model: Xserve3,1, BootROM XS31.0081.B04, 8 processors, Quad-Core Intel Xeon, 2.26 GHz, 6 GB, SMC 1.43f4
+Graphics: NVIDIA GeForce GT 120, NVIDIA GeForce GT 120, PCIe, 256 MB
+Memory Module: global_name
+Network Service: Ethernet 2, Ethernet, en1
+PCI Card: NVIDIA GeForce GT 120, sppci_displaycontroller, MXM-Slot
+Serial ATA Device: OPTIARC DVD RW AD-5670S
+""".format(process_name=process_name, pid=pid)
+
class CrashLogsTest(unittest.TestCase):
+ def assertLinesEqual(self, a, b):
+ if hasattr(self, 'assertMultiLineEqual'):
+ self.assertMultiLineEqual(a, b)
+ else:
+ self.assertEqual(a.splitlines(), b.splitlines())
+
def test_find_log_darwin(self):
if sys.platform != "darwin":
return
- older_mock_crash_report = "Older Mock Crash Report"
- mock_crash_report = "Mock Crash Report"
- newer_mock_crash_report = "Newer Mock Crash Report"
+
+ older_mock_crash_report = make_mock_crash_report_darwin('DumpRenderTree', 28528)
+ mock_crash_report = make_mock_crash_report_darwin('DumpRenderTree', 28530)
+ newer_mock_crash_report = make_mock_crash_report_darwin('DumpRenderTree', 28529)
+ other_process_mock_crash_report = make_mock_crash_report_darwin('FooProcess', 28527)
+ misformatted_mock_crash_report = 'Junk that should not appear in a crash report' + make_mock_crash_report_darwin('DumpRenderTree', 28526)[200:]
files = {}
- files['/Users/mock/Library/Logs/DiagnosticReports/TextMate_2011-06-13-150718_quadzen.crash'] = older_mock_crash_report
- files['/Users/mock/Library/Logs/DiagnosticReports/TextMate_2011-06-13-150719_quadzen.crash'] = mock_crash_report
- files['/Users/mock/Library/Logs/DiagnosticReports/TextMate_2011-06-13-150720_quadzen.crash'] = newer_mock_crash_report
- xattrs = {}
- xattrs['/Users/mock/Library/Logs/DiagnosticReports/TextMate_2011-06-13-150718_quadzen.crash'] = {}
- xattrs['/Users/mock/Library/Logs/DiagnosticReports/TextMate_2011-06-13-150719_quadzen.crash'] = {'app_description': 'TextMate[28530] version ??? (???)'}
- xattrs['/Users/mock/Library/Logs/DiagnosticReports/TextMate_2011-06-13-150720_quadzen.crash'] = {'app_description': 'TextMate[28529] version ??? (???)'}
- filesystem = MockFileSystem(files, xattrs=xattrs)
+ files['/Users/mock/Library/Logs/DiagnosticReports/DumpRenderTree_2011-06-13-150718_quadzen.crash'] = older_mock_crash_report
+ files['/Users/mock/Library/Logs/DiagnosticReports/DumpRenderTree_2011-06-13-150719_quadzen.crash'] = mock_crash_report
+ files['/Users/mock/Library/Logs/DiagnosticReports/DumpRenderTree_2011-06-13-150720_quadzen.crash'] = newer_mock_crash_report
+ files['/Users/mock/Library/Logs/DiagnosticReports/DumpRenderTree_2011-06-13-150721_quadzen.crash'] = None
+ files['/Users/mock/Library/Logs/DiagnosticReports/DumpRenderTree_2011-06-13-150722_quadzen.crash'] = other_process_mock_crash_report
+ files['/Users/mock/Library/Logs/DiagnosticReports/DumpRenderTree_2011-06-13-150723_quadzen.crash'] = misformatted_mock_crash_report
+ filesystem = MockFileSystem(files)
crash_logs = CrashLogs(filesystem)
- log = crash_logs.find_newest_log("TextMate")
- self.assertEqual(log, newer_mock_crash_report)
- log = crash_logs.find_newest_log("TextMate", 28529)
- self.assertEqual(log, newer_mock_crash_report)
- log = crash_logs.find_newest_log("TextMate", 28530)
- self.assertEqual(log, mock_crash_report)
- log = crash_logs.find_newest_log("TextMate", 28531)
+ log = crash_logs.find_newest_log("DumpRenderTree")
+ self.assertLinesEqual(log, newer_mock_crash_report)
+ log = crash_logs.find_newest_log("DumpRenderTree", 28529)
+ self.assertLinesEqual(log, newer_mock_crash_report)
+ log = crash_logs.find_newest_log("DumpRenderTree", 28530)
+ self.assertLinesEqual(log, mock_crash_report)
+ log = crash_logs.find_newest_log("DumpRenderTree", 28531)
self.assertEqual(log, None)
Modified: trunk/Tools/Scripts/webkitpy/common/system/filesystem.py (102353 => 102354)
--- trunk/Tools/Scripts/webkitpy/common/system/filesystem.py 2011-12-08 19:12:34 UTC (rev 102353)
+++ trunk/Tools/Scripts/webkitpy/common/system/filesystem.py 2011-12-08 19:16:14 UTC (rev 102354)
@@ -119,14 +119,6 @@
def getcwd(self):
return os.getcwd()
- def getxattr(self, path, attribute_name):
- if sys.platform != 'darwin':
- # We only know how to read extended attributes on Darwin. Darwin raises a KeyError when
- # the attribute doesn't exist, so mimic that.
- raise KeyError(attribute_name)
- import xattr
- return xattr.getxattr(path, attribute_name)
-
def glob(self, path):
return glob.glob(path)
Modified: trunk/Tools/Scripts/webkitpy/common/system/filesystem_mock.py (102353 => 102354)
--- trunk/Tools/Scripts/webkitpy/common/system/filesystem_mock.py 2011-12-08 19:12:34 UTC (rev 102353)
+++ trunk/Tools/Scripts/webkitpy/common/system/filesystem_mock.py 2011-12-08 19:16:14 UTC (rev 102354)
@@ -26,6 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+import StringIO
import errno
import hashlib
import os
@@ -36,7 +37,7 @@
class MockFileSystem(object):
- def __init__(self, files=None, dirs=None, cwd='/', xattrs=None):
+ def __init__(self, files=None, dirs=None, cwd='/'):
"""Initializes a "mock" filesystem that can be used to completely
stub out a filesystem.
@@ -44,9 +45,6 @@
files: a dict of filenames -> file contents. A file contents
value of None is used to indicate that the file should
not exist.
- dirs: a sequence of directory names
- cwd: the path against which relative paths should be resolved.
- xattrs: a dict of filenames -> dict of attribute names -> values.
"""
self.files = files or {}
self.written_files = {}
@@ -60,9 +58,6 @@
while not d in self.dirs:
self.dirs.add(d)
d = self.dirname(d)
- self.xattrs = {} if xattrs is None else xattrs
- for f in self.xattrs:
- assert f in self.files, f
def _get_sep(self):
return self._sep
@@ -153,9 +148,6 @@
def getcwd(self):
return self.cwd
- def getxattr(self, path, attribute_name):
- return self.xattrs[path][attribute_name]
-
def glob(self, glob_string):
# FIXME: This handles '*', but not '?', '[', or ']'.
glob_string = re.escape(glob_string)
@@ -289,7 +281,7 @@
def open_text_file_for_reading(self, path):
if self.files[path] is None:
self._raise_not_found(path)
- return ReadableTextFileObject(self, path)
+ return ReadableTextFileObject(self, path, self.files[path])
def open_text_file_for_writing(self, path):
return WritableTextFileObject(self, path)
@@ -362,7 +354,7 @@
class ReadableBinaryFileObject(object):
- def __init__(self, fs, path, data=""
+ def __init__(self, fs, path, data):
self.fs = fs
self.path = path
self.closed = False
@@ -387,5 +379,18 @@
class ReadableTextFileObject(ReadableBinaryFileObject):
- def read(self, bytes=None):
- return ReadableBinaryFileObject.read(self, bytes).decode('utf-8')
+ def __init__(self, fs, path, data):
+ super(ReadableTextFileObject, self).__init__(fs, path, StringIO.StringIO(data))
+
+ def close(self):
+ self.data.close()
+ super(ReadableTextFileObject, self).close()
+
+ def read(self, bytes=-1):
+ return self.data.read(bytes)
+
+ def readline(self, length=None):
+ return self.data.readline(length)
+
+ def seek(self, offset, whence=os.SEEK_SET):
+ self.data.seek(offset, whence)
Modified: trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py (102353 => 102354)
--- trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py 2011-12-08 19:12:34 UTC (rev 102353)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py 2011-12-08 19:16:14 UTC (rev 102354)
@@ -61,6 +61,7 @@
from webkitpy.common import array_stream
from webkitpy.common.system import outputcapture
+from webkitpy.common.system.crashlogs_unittest import make_mock_crash_report_darwin
from webkitpy.common.host_mock import MockHost
from webkitpy.layout_tests import port
@@ -494,7 +495,7 @@
self.assertTrue(fs.read_text_file('/tmp/layout-test-results/full_results.json').find('"num_regressions":0') != -1)
def test_crash_log(self):
- mock_crash_report = 'mock-crash-report'
+ mock_crash_report = make_mock_crash_report_darwin('DumpRenderTree', 12345)
fs = unit_test_filesystem()
fs.write_text_file('/Users/mock/Library/Logs/DiagnosticReports/DumpRenderTree_2011-06-13-150719_quadzen.crash', mock_crash_report)
res, buildbot_output, regular_output, user = logging_run([
@@ -510,7 +511,7 @@
self.assertEquals(fs.read_text_file('/tmp/layout-test-results/failures/unexpected/crash-with-stderr-crash-log.txt'), expected_crash_log)
def test_web_process_crash_log(self):
- mock_crash_report = 'mock-crash-report'
+ mock_crash_report = make_mock_crash_report_darwin('WebProcess', 12345)
fs = unit_test_filesystem()
fs.write_text_file('/Users/mock/Library/Logs/DiagnosticReports/WebProcess_2011-06-13-150719_quadzen.crash', mock_crash_report)
res, buildbot_output, regular_output, user = logging_run([