diff --git a/CHANGELOG.md b/CHANGELOG.md index c9c723bc5ca..731a2196832 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- Missing `mechanism.handled` is not considered crash (#3353) + ## 8.14.1 ### Fixes diff --git a/Sources/Sentry/SentryHub.m b/Sources/Sentry/SentryHub.m index bea6b6a0800..09d5911a32f 100644 --- a/Sources/Sentry/SentryHub.m +++ b/Sources/Sentry/SentryHub.m @@ -642,7 +642,7 @@ - (BOOL)envelopeContainsEventWithErrorOrHigher:(NSArray *) SentryLevel level = sentryLevelForString(eventJson[@"level"]); if (level >= kSentryLevelError) { - *handled = [self eventContainsUnhandledError:eventJson]; + *handled = [self eventContainsOnlyHandledErrors:eventJson]; return YES; } } @@ -650,14 +650,14 @@ - (BOOL)envelopeContainsEventWithErrorOrHigher:(NSArray *) return NO; } -- (BOOL)eventContainsUnhandledError:(NSDictionary *)eventDictionary +- (BOOL)eventContainsOnlyHandledErrors:(NSDictionary *)eventDictionary { NSArray *exceptions = eventDictionary[@"exception"][@"values"]; for (NSDictionary *exception in exceptions) { NSDictionary *mechanism = exception[@"mechanism"]; NSNumber *handled = mechanism[@"handled"]; - if ([handled boolValue] == NO) { + if (handled != nil && [handled boolValue] == NO) { return NO; } } diff --git a/Tests/SentryTests/SentryHubTests.swift b/Tests/SentryTests/SentryHubTests.swift index dfebbd6eb1e..015efdbdf4f 100644 --- a/Tests/SentryTests/SentryHubTests.swift +++ b/Tests/SentryTests/SentryHubTests.swift @@ -2,6 +2,7 @@ import Sentry import SentryTestUtils import XCTest +// swiftlint:disable file_length class SentryHubTests: XCTestCase { private static let dsnAsString = TestConstants.dsnAsString(username: "SentryHubTests") @@ -656,6 +657,14 @@ class SentryHubTests: XCTestCase { assertSessionWithIncrementedErrorCountedAdded() } + func testCaptureEnvelope_WithEventWithoutExceptionMechanism() { + sut.startSession() + + captureFatalEventWithoutExceptionMechanism() + + assertSessionWithIncrementedErrorCountedAdded() + } + func testCaptureEnvelope_WithEventWithFatal() { sut.startSession() @@ -864,12 +873,49 @@ class SentryHubTests: XCTestCase { group.wait() } + func testEventContainsOnlyHandledErrors() { + let sut = fixture.getSut() + XCTAssertFalse(sut.eventContainsOnlyHandledErrors(["exception": + ["values": + [["mechanism": ["handled": false]]] + ] + ])) + + XCTAssertTrue(sut.eventContainsOnlyHandledErrors(["exception": + ["values": + [["mechanism": ["handled": true]], + ["mechanism": ["handled": true]]] + ] + ])) + + XCTAssertFalse(sut.eventContainsOnlyHandledErrors(["exception": + ["values": + [["mechanism": ["handled": true]], + ["mechanism": ["handled": false]]] + ] + ])) + + XCTAssertTrue(sut.eventContainsOnlyHandledErrors(["exception": + ["values": + [["mechanism": ["handled": true]], + ["mechanism": ["other-key": false]]] + ] + ])) + } + private func captureEventEnvelope(level: SentryLevel) { let event = TestData.event event.level = level sut.capture(SentryEnvelope(event: event)) } + private func captureFatalEventWithoutExceptionMechanism() { + let event = TestData.event + event.level = SentryLevel.fatal + event.exceptions?[0].mechanism = nil + sut.capture(SentryEnvelope(event: event)) + } + private func givenCrashedSession() { fixture.sentryCrash.internalCrashedLastLaunch = true fixture.fileManager.storeCrashedSession(fixture.crashedSession) diff --git a/Tests/SentryTests/State/SentryHub+Test.h b/Tests/SentryTests/State/SentryHub+Test.h index 1d4f2e87b77..9a0102ab812 100644 --- a/Tests/SentryTests/State/SentryHub+Test.h +++ b/Tests/SentryTests/State/SentryHub+Test.h @@ -16,6 +16,7 @@ SentryHub () - (NSArray> *)installedIntegrations; - (NSSet *)installedIntegrationNames; +- (BOOL)eventContainsOnlyHandledErrors:(NSDictionary *)eventDictionary; @end NS_ASSUME_NONNULL_END