123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 |
- import pytest
- from sentry.grouping.api import get_default_grouping_config_dict, load_grouping_config
- from sentry.stacktraces.processing import (
- find_stacktraces_in_data,
- get_crash_frame_from_event_data,
- normalize_stacktraces_for_grouping,
- )
- from sentry.testutils import TestCase
- class FindStacktracesTest(TestCase):
- def test_stacktraces_basics(self):
- data = {
- "message": "hello",
- "platform": "javascript",
- "stacktrace": {
- "frames": [
- {
- "abs_path": "http://example.com/foo.js",
- "filename": "foo.js",
- "lineno": 4,
- "colno": 0,
- },
- {
- "abs_path": "http://example.com/foo.js",
- "filename": "foo.js",
- "lineno": 1,
- "colno": 0,
- "platform": "native",
- },
- ]
- },
- }
- infos = find_stacktraces_in_data(data)
- assert len(infos) == 1
- assert len(infos[0].stacktrace["frames"]) == 2
- assert infos[0].platforms == {"javascript", "native"}
- def test_stacktraces_exception(self):
- data = {
- "message": "hello",
- "platform": "javascript",
- "exception": {
- "values": [
- {
- "type": "Error",
- "stacktrace": {
- "frames": [
- {
- "abs_path": "http://example.com/foo.js",
- "filename": "foo.js",
- "lineno": 4,
- "colno": 0,
- },
- {
- "abs_path": "http://example.com/foo.js",
- "filename": "foo.js",
- "lineno": 1,
- "colno": 0,
- },
- ]
- },
- }
- ]
- },
- }
- infos = find_stacktraces_in_data(data)
- assert len(infos) == 1
- assert len(infos[0].stacktrace["frames"]) == 2
- def test_stacktraces_threads(self):
- data = {
- "message": "hello",
- "platform": "javascript",
- "threads": {
- "values": [
- {
- "id": "4711",
- "stacktrace": {
- "frames": [
- {
- "abs_path": "http://example.com/foo.js",
- "filename": "foo.js",
- "lineno": 4,
- "colno": 0,
- },
- {
- "abs_path": "http://example.com/foo.js",
- "filename": "foo.js",
- "lineno": 1,
- "colno": 0,
- },
- ]
- },
- }
- ]
- },
- }
- infos = find_stacktraces_in_data(data)
- assert len(infos) == 1
- assert len(infos[0].stacktrace["frames"]) == 2
- def test_find_stacktraces_skip_none(self):
- # This tests:
- # 1. exception is None
- # 2. stacktrace is None
- # 3. frames is None
- # 3. frames contains only None
- # 4. frame is None
- data = {
- "message": "hello",
- "platform": "javascript",
- "exception": {
- "values": [
- None,
- {"type": "Error", "stacktrace": None},
- {"type": "Error", "stacktrace": {"frames": None}},
- {"type": "Error", "stacktrace": {"frames": [None]}},
- {
- "type": "Error",
- "stacktrace": {
- "frames": [
- None,
- {
- "abs_path": "http://example.com/foo.js",
- "filename": "foo.js",
- "lineno": 4,
- "colno": 0,
- },
- {
- "abs_path": "http://example.com/foo.js",
- "filename": "foo.js",
- "lineno": 1,
- "colno": 0,
- },
- ]
- },
- },
- ]
- },
- }
- infos = find_stacktraces_in_data(data, with_exceptions=True)
- assert len(infos) == 4
- assert sum(1 for x in infos if x.stacktrace) == 3
- assert sum(1 for x in infos if x.is_exception) == 4
- # XXX: The null frame is still part of this stack trace!
- assert len(infos[3].stacktrace["frames"]) == 3
- infos = find_stacktraces_in_data(data)
- assert len(infos) == 1
- # XXX: The null frame is still part of this stack trace!
- assert len(infos[0].stacktrace["frames"]) == 3
- class NormalizeInApptest(TestCase):
- def test_normalize_with_system_frames(self):
- data = {
- "stacktrace": {
- "frames": [
- None,
- {
- "abs_path": "http://example.com/foo.js",
- "filename": "foo.js",
- "lineno": 4,
- "colno": 0,
- "in_app": True,
- },
- {
- "abs_path": "http://example.com/foo.js",
- "filename": "foo.js",
- "lineno": 1,
- "colno": 0,
- },
- ]
- }
- }
- normalize_stacktraces_for_grouping(data)
- assert data["stacktrace"]["frames"][1]["in_app"] is True
- assert data["stacktrace"]["frames"][2]["in_app"] is False
- def test_normalize_skips_none(self):
- data = {
- "stacktrace": {
- "frames": [
- None,
- {
- "abs_path": "http://example.com/foo.js",
- "filename": "foo.js",
- "lineno": 4,
- "colno": 0,
- },
- {
- "abs_path": "http://example.com/foo.js",
- "filename": "foo.js",
- "lineno": 1,
- "colno": 0,
- },
- ]
- }
- }
- normalize_stacktraces_for_grouping(data)
- assert data["stacktrace"]["frames"][1]["in_app"] is False
- assert data["stacktrace"]["frames"][2]["in_app"] is False
- def test_ios_package_in_app_detection(self):
- data = {
- "platform": "native",
- "stacktrace": {
- "frames": [
- {
- "package": "/var/containers/Bundle/Application/B33C37A8-F933-4B6B-9FFA-152282BFDF13/SentryTest.app/SentryTest",
- "instruction_addr": "0x1000",
- },
- {
- "package": "/var/containers/Bundle/Application/B33C37A8-F933-4B6B-9FFA-152282BFDF13/SentryTest.app/Frameworks/foo.dylib",
- "instruction_addr": "0x2000",
- },
- {
- "package": "/var/containers/Bundle/Application/B33C37A8-F933-4B6B-9FFA-152282BFDF13/SentryTest.app/Frameworks/libswiftCore.dylib",
- "instruction_addr": "0x3000",
- },
- {"package": "/usr/lib/whatever.dylib", "instruction_addr": "0x4000"},
- ]
- },
- }
- config = load_grouping_config(get_default_grouping_config_dict())
- normalize_stacktraces_for_grouping(data, grouping_config=config)
- # App object should be in_app
- assert data["stacktrace"]["frames"][0]["in_app"] is True
- # Framework should be in app (but optional)
- assert data["stacktrace"]["frames"][1]["in_app"] is True
- # libswift should not be system
- assert data["stacktrace"]["frames"][2]["in_app"] is False
- # Unknown object should default to not in_app
- assert data["stacktrace"]["frames"][3]["in_app"] is False
- def tes_macos_package_in_app_detection(self):
- data = {
- "platform": "cocoa",
- "debug_meta": {"images": []}, # omitted
- "exception": {
- "values": [
- {
- "stacktrace": {
- "frames": [
- {
- "function": "-[CRLCrashAsyncSafeThread crash]",
- "package": "/Users/haza/Library/Developer/Xcode/Archives/2017-06-19/CrashProbe 19-06-2017, 08.53.xcarchive/Products/Applications/CrashProbe.app/Contents/Frameworks/CrashLib.framework/Versions/A/CrashLib",
- "instruction_addr": 4295098388,
- },
- {
- "function": "[KSCrash ]",
- "package": "/usr/lib/system/libdyld.dylib",
- "instruction_addr": 4295098388,
- },
- ]
- },
- "type": "NSRangeException",
- }
- ]
- },
- "contexts": {"os": {"version": "10.12.5", "type": "os", "name": "macOS"}},
- }
- config = load_grouping_config(get_default_grouping_config_dict())
- normalize_stacktraces_for_grouping(data, grouping_config=config)
- frames = data["exception"]["values"][0]["stacktrace"]["frames"]
- assert frames[0]["in_app"] is True
- assert frames[1]["in_app"] is False
- def ios_function_name_in_app_detection(self, function, isInApp: bool):
- data = {
- "platform": "cocoa",
- "debug_meta": {"images": []}, # omitted
- "exception": {
- "values": [
- {
- "stacktrace": {
- "frames": [
- {
- "function": function,
- "package": "/var/containers/Bundle/Application/B33C37A8-F933-4B6B-9FFA-152282BFDF13/SentryTest.app/SentryTest",
- "instruction_addr": 4295098388,
- },
- # We need two frames otherwise all frames are inApp
- {
- "function": "[KSCrash ]",
- "package": "/usr/lib/system/libdyld.dylib",
- "instruction_addr": 4295098388,
- },
- ]
- },
- "type": "NSRangeException",
- }
- ]
- },
- "contexts": {"os": {"version": "9.3.2", "type": "os", "name": "iOS"}},
- }
- config = load_grouping_config(get_default_grouping_config_dict())
- normalize_stacktraces_for_grouping(data, grouping_config=config)
- frames = data["exception"]["values"][0]["stacktrace"]["frames"]
- assert frames[0]["in_app"] is isInApp, (
- "For function: " + function + " expected:" + str(isInApp)
- )
- def test_ios_function_name_in_app_detection(self):
- self.ios_function_name_in_app_detection(
- function="sentrycrash__hook_dispatch_async", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="sentrycrash__hook_dispatch_after_f", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="sentrycrash__async_backtrace_capture", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="__sentrycrash__hook_dispatch_async_block_invoke", isInApp=False
- )
- self.ios_function_name_in_app_detection(function="kscm_f", isInApp=False)
- self.ios_function_name_in_app_detection(function="kscm_", isInApp=False)
- self.ios_function_name_in_app_detection(function=" kscm_", isInApp=False)
- self.ios_function_name_in_app_detection(function="kscm", isInApp=True)
- self.ios_function_name_in_app_detection(function="sentrycrashcm_f", isInApp=False)
- self.ios_function_name_in_app_detection(function="sentrycrashcm_", isInApp=False)
- self.ios_function_name_in_app_detection(function=" sentrycrashcm_", isInApp=False)
- self.ios_function_name_in_app_detection(function="sentrycrashcm", isInApp=True)
- self.ios_function_name_in_app_detection(function="kscrash_f", isInApp=False)
- self.ios_function_name_in_app_detection(function="kscrash_", isInApp=False)
- self.ios_function_name_in_app_detection(function=" kscrash_", isInApp=False)
- self.ios_function_name_in_app_detection(function="kscrash", isInApp=True)
- self.ios_function_name_in_app_detection(function="sentrycrash_f", isInApp=False)
- self.ios_function_name_in_app_detection(function="sentrycrash_", isInApp=False)
- self.ios_function_name_in_app_detection(function=" sentrycrash_", isInApp=False)
- self.ios_function_name_in_app_detection(function="sentrycrash", isInApp=True)
- self.ios_function_name_in_app_detection(function="+[KSCrash ]", isInApp=False)
- self.ios_function_name_in_app_detection(function="-[KSCrash]", isInApp=False)
- self.ios_function_name_in_app_detection(function="-[KSCrashy]", isInApp=False)
- self.ios_function_name_in_app_detection(function="-[MyKSCrashy ", isInApp=True)
- self.ios_function_name_in_app_detection(function="+[RNSentry ]", isInApp=False)
- self.ios_function_name_in_app_detection(function="-[RNSentry]", isInApp=False)
- self.ios_function_name_in_app_detection(function="-[RNSentry]", isInApp=False)
- self.ios_function_name_in_app_detection(function="-[MRNSentry ]", isInApp=True)
- self.ios_function_name_in_app_detection(function="+[Sentry ]", isInApp=False)
- self.ios_function_name_in_app_detection(function="-[Sentry]", isInApp=False)
- self.ios_function_name_in_app_detection(function="-[Sentry]", isInApp=False)
- self.ios_function_name_in_app_detection(function="-[MSentry capture]", isInApp=True)
- self.ios_function_name_in_app_detection(
- function="-[SentryHub captureMessage]", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="-[SentryClient captureMessage]", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="+[SentrySDK captureMessage]", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="-[SentryStacktraceBuilder buildStacktraceForCurrentThread]", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="-[SentryThreadInspector getCurrentThreads]", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="-[SentryClient captureMessage:withScope:]", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="-[SentryFrameInAppLogic isInApp:]", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="-[SentryFrameRemover removeNonSdkFrames:]", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="-[SentryDebugMetaBuilder buildDebugMeta:withScope:]", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="-[SentryCrashAdapter crashedLastLaunch]", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="-[SentryCrashAdapter isRateLimitActive:]", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="-[SentryTransport sendEvent:attachments:]", isInApp=False
- )
- self.ios_function_name_in_app_detection(
- function="-[SentryHttpTransport sendEvent:attachments:]", isInApp=False
- )
- @pytest.mark.parametrize(
- "event",
- [
- {"threads": {"values": [{"stacktrace": {"frames": [{"in_app": True, "marco": "polo"}]}}]}},
- {
- "exception": {
- "values": [{"stacktrace": {"frames": [{"in_app": True, "marco": "polo"}]}}]
- }
- },
- {"stacktrace": {"frames": [{"in_app": True, "marco": "polo"}]}},
- ],
- )
- def test_get_crash_frame(event):
- assert get_crash_frame_from_event_data(event)["marco"] == "polo"
|