diff --git a/CHANGELOG.md b/CHANGELOG.md index b78db735..4b86f54c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- fix: beforeSend dropping events if not set in options ([#79](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/79)) + ## 0.1.0 ### Features diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.kt index c245a51e..973de837 100644 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.kt +++ b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.kt @@ -51,12 +51,15 @@ internal fun CocoaSentryOptions.applyCocoaBaseOptions(options: SentryOptions) { event?.sdk = sdk - val modifiedEvent = event?.let { SentryEvent(it) }?.let { unwrappedEvent -> - val result = options.beforeSend?.invoke(unwrappedEvent) - result?.let { event.applyKmpEvent(it) } + if (options.beforeSend == null) { + dropKotlinCrashEvent(event as NSExceptionSentryEvent?) as CocoaSentryEvent? + } else { + val modifiedEvent = event?.let { SentryEvent(it) }?.let { unwrappedEvent -> + val result = options.beforeSend?.invoke(unwrappedEvent) + result?.let { event.applyKmpEvent(it) } + } + dropKotlinCrashEvent(modifiedEvent as NSExceptionSentryEvent?) as CocoaSentryEvent? } - - dropKotlinCrashEvent(modifiedEvent as NSExceptionSentryEvent?) as CocoaSentryEvent? } val sdkName = options.sdk?.name ?: BuildKonfig.SENTRY_KMP_COCOA_SDK_NAME diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt new file mode 100644 index 00000000..9577fd61 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt @@ -0,0 +1,25 @@ +package io.sentry.kotlin.multiplatform + +import io.sentry.kotlin.multiplatform.extensions.applyCocoaBaseOptions + +actual class SentryEventConfigurator { + private val cocoaSentryEvent = CocoaSentryEvent() + actual val originalEvent: SentryEvent = SentryEvent(cocoaSentryEvent) + + actual fun applyOptions(optionsConfiguration: OptionsConfiguration): SentryEvent? { + val kmpOptions = SentryOptions() + optionsConfiguration.invoke(kmpOptions) + return applyOptions(kmpOptions) + } + + actual fun applyOptions(options: SentryOptions): SentryEvent? { + val cocoaOptions = CocoaSentryOptions() + cocoaOptions.applyCocoaBaseOptions(options) + val cocoaModifiedSentryEvent = cocoaOptions.beforeSend?.invoke(cocoaSentryEvent) + return if (cocoaModifiedSentryEvent == null) { + null + } else { + SentryEvent(cocoaModifiedSentryEvent) + } + } +} diff --git a/sentry-kotlin-multiplatform/src/commonJvmMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.kt b/sentry-kotlin-multiplatform/src/commonJvmMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.kt index 7275cca7..f793dda9 100644 --- a/sentry-kotlin-multiplatform/src/commonJvmMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.kt +++ b/sentry-kotlin-multiplatform/src/commonJvmMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.kt @@ -44,8 +44,12 @@ internal fun JvmSentryOptions.applyJvmBaseOptions(options: SentryOptions) { options.beforeBreadcrumb?.invoke(jvmBreadcrumb.toKmpBreadcrumb())?.toJvmBreadcrumb() } setBeforeSend { jvmSentryEvent, hint -> - options.beforeSend?.invoke(SentryEvent(jvmSentryEvent))?.let { - jvmSentryEvent.applyKmpEvent(it) + if (options.beforeSend == null) { + jvmSentryEvent + } else { + options.beforeSend?.invoke(SentryEvent(jvmSentryEvent))?.let { + jvmSentryEvent.applyKmpEvent(it) + } } } } diff --git a/sentry-kotlin-multiplatform/src/commonJvmTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt b/sentry-kotlin-multiplatform/src/commonJvmTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt new file mode 100644 index 00000000..2122bc80 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/commonJvmTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt @@ -0,0 +1,27 @@ +package io.sentry.kotlin.multiplatform + +import io.sentry.Hint +import io.sentry.kotlin.multiplatform.extensions.applyJvmBaseOptions + +actual class SentryEventConfigurator { + private val jvmSentryEvent = JvmSentryEvent() + actual val originalEvent: SentryEvent = SentryEvent(jvmSentryEvent) + + actual fun applyOptions(optionsConfiguration: OptionsConfiguration): SentryEvent? { + val kmpOptions = SentryOptions() + optionsConfiguration.invoke(kmpOptions) + return applyOptions(kmpOptions) + } + + actual fun applyOptions(options: SentryOptions): SentryEvent? { + val jvmOptions = JvmSentryOptions() + jvmOptions.applyJvmBaseOptions(options) + val jvmHint = Hint() + val jvmModifiedSentryEvent = jvmOptions.beforeSend?.execute(jvmSentryEvent, jvmHint) + return if (jvmModifiedSentryEvent == null) { + null + } else { + SentryEvent(jvmModifiedSentryEvent) + } + } +} diff --git a/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/BeforeSendIntegrationTest.kt b/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/BeforeSendIntegrationTest.kt new file mode 100644 index 00000000..b9e71e3d --- /dev/null +++ b/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/BeforeSendIntegrationTest.kt @@ -0,0 +1,250 @@ +package io.sentry.kotlin.multiplatform + +import io.sentry.kotlin.multiplatform.protocol.Breadcrumb +import io.sentry.kotlin.multiplatform.protocol.Message +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class BeforeSendIntegrationTest { + private val sentryEventConfigurator = SentryEventConfigurator() + + @Test + fun `event is not null if KMP beforeSend option is null`() { + val event = sentryEventConfigurator.applyOptions() + assertNotNull(event) + } + + @Test + fun `event is null if KMP beforeSend callback config returns null`() { + val event = sentryEventConfigurator.applyOptions { + it.beforeSend = { + null + } + } + assertNull(event) + } + + @Test + fun `event is not null if KMP beforeSend callback config returns not null`() { + val event = sentryEventConfigurator.applyOptions { + it.beforeSend = { event -> + event + } + } + assertNotNull(event) + } + + @Test + fun `event logger is modified if KMP beforeSend callback config modifies it`() { + val expected = "test" + val event = sentryEventConfigurator.applyOptions { + it.beforeSend = { event -> + event.logger = expected + event + } + } + assertNotNull(event) + assertEquals(expected, event.logger) + } + + @Test + fun `event level is modified if KMP beforeSend callback config modifies it`() { + val expected = SentryLevel.DEBUG + val event = sentryEventConfigurator.applyOptions { + it.beforeSend = { event -> + event.level = expected + event + } + } + assertNotNull(event) + assertEquals(expected, event.level) + } + + @Test + fun `event message is modified if KMP beforeSend callback config modifies it`() { + val expected = Message("test") + val event = sentryEventConfigurator.applyOptions { + it.beforeSend = { event -> + event.message = expected + event + } + } + assertNotNull(event) + assertEquals(expected, event.message) + } + + @Test + fun `event release is modified if KMP beforeSend callback config modifies it`() { + val expected = "test" + val event = sentryEventConfigurator.applyOptions { + it.beforeSend = { event -> + event.release = expected + event + } + } + assertNotNull(event) + assertEquals(expected, event.release) + } + + @Test + fun `event environment is modified if KMP beforeSend callback config modifies it`() { + val expected = "test" + val event = sentryEventConfigurator.applyOptions { + it.beforeSend = { event -> + event.environment = expected + event + } + } + assertNotNull(event) + assertEquals(expected, event.environment) + } + + @Test + fun `event serverName is modified if KMP beforeSend callback config modifies it`() { + val expected = "test" + val event = sentryEventConfigurator.applyOptions { + it.beforeSend = { event -> + event.serverName = expected + event + } + } + assertNotNull(event) + assertEquals(expected, event.serverName) + } + + @Test + fun `event dist is modified if KMP beforeSend callback config modifies it`() { + val expected = "test" + val event = sentryEventConfigurator.applyOptions { + it.beforeSend = { event -> + event.dist = expected + event + } + } + assertNotNull(event) + assertEquals(expected, event.dist) + } + + @Test + fun `event fingerprint is modified if KMP beforeSend callback config modifies it`() { + val expected = mutableListOf("test") + val event = sentryEventConfigurator.applyOptions { + it.beforeSend = { event -> + event.fingerprint = expected + event + } + } + assertNotNull(event) + assertEquals(expected, event.fingerprint) + } + + @Test + fun `event tags are modified if KMP beforeSend callback config modifies it`() { + val expected = mutableMapOf("test" to "test") + val event = sentryEventConfigurator.applyOptions { + it.beforeSend = { event -> + event.tags = expected + event + } + } + assertNotNull(event) + assertEquals(expected, event.tags) + } + + @Test + fun `event breadcrumbs are modified if KMP beforeSend callback config modifies it`() { + val expected = mutableListOf(Breadcrumb.debug("test")) + val event = sentryEventConfigurator.applyOptions { + it.beforeSend = { event -> + event.breadcrumbs = expected + event + } + } + assertNotNull(event) + assertEquals(expected.first().type, event.breadcrumbs.first().type) + assertEquals(expected.first().message, event.breadcrumbs.first().message) + assertEquals(expected.first().level, event.breadcrumbs.first().level) + } + + @Test + fun `event logger is not modified if KMP beforeSend callback config is not modified`() { + val originalEvent = sentryEventConfigurator.originalEvent + val event = sentryEventConfigurator.applyOptions() + assertNotNull(event) + assertEquals(originalEvent.logger, event.logger) + } + + @Test + fun `event level is not modified if KMP beforeSend callback config is not modified`() { + val originalEvent = sentryEventConfigurator.originalEvent + val event = sentryEventConfigurator.applyOptions() + assertNotNull(event) + assertEquals(originalEvent.level, event.level) + } + + @Test + fun `event message is not modified if KMP beforeSend callback config is not modified`() { + val originalEvent = sentryEventConfigurator.originalEvent + val event = sentryEventConfigurator.applyOptions() + assertNotNull(event) + assertEquals(originalEvent.message, event.message) + } + + @Test + fun `event release is not modified if KMP beforeSend callback config is not modified`() { + val originalEvent = sentryEventConfigurator.originalEvent + val event = sentryEventConfigurator.applyOptions() + assertNotNull(event) + assertEquals(originalEvent.release, event.release) + } + + @Test + fun `event environment is not modified if KMP beforeSend callback config is not modified`() { + val originalEvent = sentryEventConfigurator.originalEvent + val event = sentryEventConfigurator.applyOptions() + assertNotNull(event) + assertEquals(originalEvent.environment, event.environment) + } + + @Test + fun `event serverName is not modified if KMP beforeSend callback config is not modified`() { + val originalEvent = sentryEventConfigurator.originalEvent + val event = sentryEventConfigurator.applyOptions() + assertNotNull(event) + assertEquals(originalEvent.serverName, event.serverName) + } + + @Test + fun `event dist is not modified if KMP beforeSend callback config is not modified`() { + val originalEvent = sentryEventConfigurator.originalEvent + val event = sentryEventConfigurator.applyOptions() + assertNotNull(event) + assertEquals(originalEvent.dist, event.dist) + } + + @Test + fun `event fingerprint is not modified if KMP beforeSend callback config is not modified`() { + val originalEvent = sentryEventConfigurator.originalEvent + val event = sentryEventConfigurator.applyOptions() + assertNotNull(event) + assertEquals(originalEvent.fingerprint, event.fingerprint) + } + + @Test + fun `event tags are not modified if KMP beforeSend callback config is not modified`() { + val originalEvent = sentryEventConfigurator.originalEvent + val event = sentryEventConfigurator.applyOptions() + assertNotNull(event) + assertEquals(originalEvent.tags, event.tags) + } + + @Test + fun `event breadcrumbs are not modified if KMP beforeSend callback config is not modified`() { + val originalEvent = sentryEventConfigurator.originalEvent + val event = sentryEventConfigurator.applyOptions() + assertNotNull(event) + assertEquals(originalEvent.breadcrumbs, event.breadcrumbs) + } +} diff --git a/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt b/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt new file mode 100644 index 00000000..d995661d --- /dev/null +++ b/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt @@ -0,0 +1,11 @@ +package io.sentry.kotlin.multiplatform + +/** + * This class deals with configuring and modifying a SentryEvent. + * It is used to test any code that can alter a SentryEvent. + */ +expect class SentryEventConfigurator() { + val originalEvent: SentryEvent + fun applyOptions(optionsConfiguration: OptionsConfiguration): SentryEvent? + fun applyOptions(options: SentryOptions = SentryOptions()): SentryEvent? +}