Title: [102354] trunk/Tools
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([
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to