Commit 2c177985 authored by Roger Yang's avatar Roger Yang
Browse files

Close #6953: Report native fatal crash to Sentry as level FATAL

parent ba0d00e9
......@@ -90,13 +90,18 @@ class SentryService(
override fun report(crash: Crash.NativeCodeCrash): String? {
if (sendEventForNativeCrashes) {
val level = when (crash.isFatal) {
true -> Event.Level.FATAL
else -> Event.Level.ERROR
}
crash.breadcrumbs.forEach {
client.context.recordBreadcrumb(it.toSentryBreadcrumb())
}
val eventBuilder = EventBuilder()
.withMessage(createMessage(crash))
.withLevel(Event.Level.INFO)
.withLevel(level)
client.sendEvent(eventBuilder)
client.context.clearBreadcrumbs()
......
......@@ -9,6 +9,7 @@ import io.sentry.SentryClient
import io.sentry.SentryClientFactory
import io.sentry.context.Context
import io.sentry.dsn.Dsn
import io.sentry.event.Event
import io.sentry.event.EventBuilder
import mozilla.components.lib.crash.Crash
import mozilla.components.lib.crash.CrashReporter
......@@ -24,6 +25,7 @@ import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
......@@ -31,6 +33,7 @@ import org.mockito.Mockito.spy
import org.mockito.Mockito.`when`
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.times
import java.util.Date
@RunWith(AndroidJUnit4::class)
......@@ -133,7 +136,8 @@ class SentryServiceTest {
clientFactory = object : SentryClientFactory() {
override fun createSentryClient(dsn: Dsn?): SentryClient = client
},
sendEventForNativeCrashes = true)
sendEventForNativeCrashes = true
)
service.report(Crash.NativeCodeCrash("", true, "", false, arrayListOf()))
......@@ -141,6 +145,110 @@ class SentryServiceTest {
verify(clientContext).clearBreadcrumbs()
}
@Test
fun `Fatal native code crashes are reported as level FATAL`() {
val client: SentryClient = mock()
val clientContext: Context = mock()
doReturn(clientContext).`when`(client).context
doNothing().`when`(clientContext).clearBreadcrumbs()
val service = SentryService(
testContext,
"https://not:real6@sentry.prod.example.net/405",
clientFactory = object : SentryClientFactory() {
override fun createSentryClient(dsn: Dsn?): SentryClient = client
},
sendEventForNativeCrashes = true
)
service.report(Crash.NativeCodeCrash("", true, "", true, arrayListOf()))
val eventBuilderCaptor: ArgumentCaptor<EventBuilder> = ArgumentCaptor.forClass(EventBuilder::class.java)
verify(client, times(1)).sendEvent(eventBuilderCaptor.capture())
val capturedEvent: List<EventBuilder> = eventBuilderCaptor.allValues
assertEquals(Event.Level.FATAL, capturedEvent[0].event.level)
verify(clientContext).clearBreadcrumbs()
}
@Test
fun `Non-fatal native code crashes are reported as level ERROR`() {
val client: SentryClient = mock()
val clientContext: Context = mock()
doReturn(clientContext).`when`(client).context
doNothing().`when`(clientContext).clearBreadcrumbs()
val service = SentryService(
testContext,
"https://not:real6@sentry.prod.example.net/405",
clientFactory = object : SentryClientFactory() {
override fun createSentryClient(dsn: Dsn?): SentryClient = client
},
sendEventForNativeCrashes = true
)
service.report(Crash.NativeCodeCrash("", true, "", false, arrayListOf()))
val eventBuilderCaptor: ArgumentCaptor<EventBuilder> = ArgumentCaptor.forClass(EventBuilder::class.java)
verify(client, times(1)).sendEvent(eventBuilderCaptor.capture())
val capturedEvent: List<EventBuilder> = eventBuilderCaptor.allValues
assertEquals(Event.Level.ERROR, capturedEvent[0].event.level)
verify(clientContext).clearBreadcrumbs()
}
@Test
fun `uncaught exception crashes are reported as level FATAL`() {
val client: SentryClient = mock()
val clientContext: Context = mock()
doReturn(clientContext).`when`(client).context
doNothing().`when`(clientContext).clearBreadcrumbs()
val service = SentryService(
testContext,
"https://not:real6@sentry.prod.example.net/405",
clientFactory = object : SentryClientFactory() {
override fun createSentryClient(dsn: Dsn?): SentryClient = client
}
)
service.report(Crash.UncaughtExceptionCrash(RuntimeException("test"), arrayListOf()))
val eventBuilderCaptor: ArgumentCaptor<EventBuilder> = ArgumentCaptor.forClass(EventBuilder::class.java)
verify(client, times(1)).sendEvent(eventBuilderCaptor.capture())
val capturedEvent: List<EventBuilder> = eventBuilderCaptor.allValues
assertEquals(Event.Level.FATAL, capturedEvent[0].event.level)
verify(clientContext).clearBreadcrumbs()
}
@Test
fun `caught exception crashes are reported as level INFO`() {
val client: SentryClient = mock()
val clientContext: Context = mock()
doReturn(clientContext).`when`(client).context
doNothing().`when`(clientContext).clearBreadcrumbs()
val service = SentryService(
testContext,
"https://not:real6@sentry.prod.example.net/405",
clientFactory = object : SentryClientFactory() {
override fun createSentryClient(dsn: Dsn?): SentryClient = client
}
)
val throwable = RuntimeException("Test")
val crashBreadCrumbs = arrayListOf<Breadcrumb>()
service.report(throwable, crashBreadCrumbs)
val eventBuilderCaptor: ArgumentCaptor<EventBuilder> = ArgumentCaptor.forClass(EventBuilder::class.java)
verify(client, times(1)).sendEvent(eventBuilderCaptor.capture())
val capturedEvent: List<EventBuilder> = eventBuilderCaptor.allValues
assertEquals(Event.Level.INFO, capturedEvent[0].event.level)
verify(clientContext).clearBreadcrumbs()
}
@Test
fun `SentryService does not send event for native code crashes by default`() {
val client: SentryClient = mock()
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment