Skip to content

Commit 10b731b

Browse files
authored
fix: beforeSend dropping events if option is not set (#79)
* add elvis operator if beforeSend invoke result is null * add sample integration test for beforeSend * add more integration tests * update docs * update changelog
1 parent 58fdd8e commit 10b731b

File tree

7 files changed

+333
-7
lines changed

7 files changed

+333
-7
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Fixes
6+
7+
- fix: beforeSend dropping events if not set in options ([#79](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/79))
8+
39
## 0.1.0
410

511
### Features

sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,15 @@ internal fun CocoaSentryOptions.applyCocoaBaseOptions(options: SentryOptions) {
5151

5252
event?.sdk = sdk
5353

54-
val modifiedEvent = event?.let { SentryEvent(it) }?.let { unwrappedEvent ->
55-
val result = options.beforeSend?.invoke(unwrappedEvent)
56-
result?.let { event.applyKmpEvent(it) }
54+
if (options.beforeSend == null) {
55+
dropKotlinCrashEvent(event as NSExceptionSentryEvent?) as CocoaSentryEvent?
56+
} else {
57+
val modifiedEvent = event?.let { SentryEvent(it) }?.let { unwrappedEvent ->
58+
val result = options.beforeSend?.invoke(unwrappedEvent)
59+
result?.let { event.applyKmpEvent(it) }
60+
}
61+
dropKotlinCrashEvent(modifiedEvent as NSExceptionSentryEvent?) as CocoaSentryEvent?
5762
}
58-
59-
dropKotlinCrashEvent(modifiedEvent as NSExceptionSentryEvent?) as CocoaSentryEvent?
6063
}
6164

6265
val sdkName = options.sdk?.name ?: BuildKonfig.SENTRY_KMP_COCOA_SDK_NAME
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package io.sentry.kotlin.multiplatform
2+
3+
import io.sentry.kotlin.multiplatform.extensions.applyCocoaBaseOptions
4+
5+
actual class SentryEventConfigurator {
6+
private val cocoaSentryEvent = CocoaSentryEvent()
7+
actual val originalEvent: SentryEvent = SentryEvent(cocoaSentryEvent)
8+
9+
actual fun applyOptions(optionsConfiguration: OptionsConfiguration): SentryEvent? {
10+
val kmpOptions = SentryOptions()
11+
optionsConfiguration.invoke(kmpOptions)
12+
return applyOptions(kmpOptions)
13+
}
14+
15+
actual fun applyOptions(options: SentryOptions): SentryEvent? {
16+
val cocoaOptions = CocoaSentryOptions()
17+
cocoaOptions.applyCocoaBaseOptions(options)
18+
val cocoaModifiedSentryEvent = cocoaOptions.beforeSend?.invoke(cocoaSentryEvent)
19+
return if (cocoaModifiedSentryEvent == null) {
20+
null
21+
} else {
22+
SentryEvent(cocoaModifiedSentryEvent)
23+
}
24+
}
25+
}

sentry-kotlin-multiplatform/src/commonJvmMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,12 @@ internal fun JvmSentryOptions.applyJvmBaseOptions(options: SentryOptions) {
4444
options.beforeBreadcrumb?.invoke(jvmBreadcrumb.toKmpBreadcrumb())?.toJvmBreadcrumb()
4545
}
4646
setBeforeSend { jvmSentryEvent, hint ->
47-
options.beforeSend?.invoke(SentryEvent(jvmSentryEvent))?.let {
48-
jvmSentryEvent.applyKmpEvent(it)
47+
if (options.beforeSend == null) {
48+
jvmSentryEvent
49+
} else {
50+
options.beforeSend?.invoke(SentryEvent(jvmSentryEvent))?.let {
51+
jvmSentryEvent.applyKmpEvent(it)
52+
}
4953
}
5054
}
5155
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package io.sentry.kotlin.multiplatform
2+
3+
import io.sentry.Hint
4+
import io.sentry.kotlin.multiplatform.extensions.applyJvmBaseOptions
5+
6+
actual class SentryEventConfigurator {
7+
private val jvmSentryEvent = JvmSentryEvent()
8+
actual val originalEvent: SentryEvent = SentryEvent(jvmSentryEvent)
9+
10+
actual fun applyOptions(optionsConfiguration: OptionsConfiguration): SentryEvent? {
11+
val kmpOptions = SentryOptions()
12+
optionsConfiguration.invoke(kmpOptions)
13+
return applyOptions(kmpOptions)
14+
}
15+
16+
actual fun applyOptions(options: SentryOptions): SentryEvent? {
17+
val jvmOptions = JvmSentryOptions()
18+
jvmOptions.applyJvmBaseOptions(options)
19+
val jvmHint = Hint()
20+
val jvmModifiedSentryEvent = jvmOptions.beforeSend?.execute(jvmSentryEvent, jvmHint)
21+
return if (jvmModifiedSentryEvent == null) {
22+
null
23+
} else {
24+
SentryEvent(jvmModifiedSentryEvent)
25+
}
26+
}
27+
}
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
package io.sentry.kotlin.multiplatform
2+
3+
import io.sentry.kotlin.multiplatform.protocol.Breadcrumb
4+
import io.sentry.kotlin.multiplatform.protocol.Message
5+
import kotlin.test.Test
6+
import kotlin.test.assertEquals
7+
import kotlin.test.assertNotNull
8+
import kotlin.test.assertNull
9+
10+
class BeforeSendIntegrationTest {
11+
private val sentryEventConfigurator = SentryEventConfigurator()
12+
13+
@Test
14+
fun `event is not null if KMP beforeSend option is null`() {
15+
val event = sentryEventConfigurator.applyOptions()
16+
assertNotNull(event)
17+
}
18+
19+
@Test
20+
fun `event is null if KMP beforeSend callback config returns null`() {
21+
val event = sentryEventConfigurator.applyOptions {
22+
it.beforeSend = {
23+
null
24+
}
25+
}
26+
assertNull(event)
27+
}
28+
29+
@Test
30+
fun `event is not null if KMP beforeSend callback config returns not null`() {
31+
val event = sentryEventConfigurator.applyOptions {
32+
it.beforeSend = { event ->
33+
event
34+
}
35+
}
36+
assertNotNull(event)
37+
}
38+
39+
@Test
40+
fun `event logger is modified if KMP beforeSend callback config modifies it`() {
41+
val expected = "test"
42+
val event = sentryEventConfigurator.applyOptions {
43+
it.beforeSend = { event ->
44+
event.logger = expected
45+
event
46+
}
47+
}
48+
assertNotNull(event)
49+
assertEquals(expected, event.logger)
50+
}
51+
52+
@Test
53+
fun `event level is modified if KMP beforeSend callback config modifies it`() {
54+
val expected = SentryLevel.DEBUG
55+
val event = sentryEventConfigurator.applyOptions {
56+
it.beforeSend = { event ->
57+
event.level = expected
58+
event
59+
}
60+
}
61+
assertNotNull(event)
62+
assertEquals(expected, event.level)
63+
}
64+
65+
@Test
66+
fun `event message is modified if KMP beforeSend callback config modifies it`() {
67+
val expected = Message("test")
68+
val event = sentryEventConfigurator.applyOptions {
69+
it.beforeSend = { event ->
70+
event.message = expected
71+
event
72+
}
73+
}
74+
assertNotNull(event)
75+
assertEquals(expected, event.message)
76+
}
77+
78+
@Test
79+
fun `event release is modified if KMP beforeSend callback config modifies it`() {
80+
val expected = "test"
81+
val event = sentryEventConfigurator.applyOptions {
82+
it.beforeSend = { event ->
83+
event.release = expected
84+
event
85+
}
86+
}
87+
assertNotNull(event)
88+
assertEquals(expected, event.release)
89+
}
90+
91+
@Test
92+
fun `event environment is modified if KMP beforeSend callback config modifies it`() {
93+
val expected = "test"
94+
val event = sentryEventConfigurator.applyOptions {
95+
it.beforeSend = { event ->
96+
event.environment = expected
97+
event
98+
}
99+
}
100+
assertNotNull(event)
101+
assertEquals(expected, event.environment)
102+
}
103+
104+
@Test
105+
fun `event serverName is modified if KMP beforeSend callback config modifies it`() {
106+
val expected = "test"
107+
val event = sentryEventConfigurator.applyOptions {
108+
it.beforeSend = { event ->
109+
event.serverName = expected
110+
event
111+
}
112+
}
113+
assertNotNull(event)
114+
assertEquals(expected, event.serverName)
115+
}
116+
117+
@Test
118+
fun `event dist is modified if KMP beforeSend callback config modifies it`() {
119+
val expected = "test"
120+
val event = sentryEventConfigurator.applyOptions {
121+
it.beforeSend = { event ->
122+
event.dist = expected
123+
event
124+
}
125+
}
126+
assertNotNull(event)
127+
assertEquals(expected, event.dist)
128+
}
129+
130+
@Test
131+
fun `event fingerprint is modified if KMP beforeSend callback config modifies it`() {
132+
val expected = mutableListOf("test")
133+
val event = sentryEventConfigurator.applyOptions {
134+
it.beforeSend = { event ->
135+
event.fingerprint = expected
136+
event
137+
}
138+
}
139+
assertNotNull(event)
140+
assertEquals(expected, event.fingerprint)
141+
}
142+
143+
@Test
144+
fun `event tags are modified if KMP beforeSend callback config modifies it`() {
145+
val expected = mutableMapOf("test" to "test")
146+
val event = sentryEventConfigurator.applyOptions {
147+
it.beforeSend = { event ->
148+
event.tags = expected
149+
event
150+
}
151+
}
152+
assertNotNull(event)
153+
assertEquals(expected, event.tags)
154+
}
155+
156+
@Test
157+
fun `event breadcrumbs are modified if KMP beforeSend callback config modifies it`() {
158+
val expected = mutableListOf(Breadcrumb.debug("test"))
159+
val event = sentryEventConfigurator.applyOptions {
160+
it.beforeSend = { event ->
161+
event.breadcrumbs = expected
162+
event
163+
}
164+
}
165+
assertNotNull(event)
166+
assertEquals(expected.first().type, event.breadcrumbs.first().type)
167+
assertEquals(expected.first().message, event.breadcrumbs.first().message)
168+
assertEquals(expected.first().level, event.breadcrumbs.first().level)
169+
}
170+
171+
@Test
172+
fun `event logger is not modified if KMP beforeSend callback config is not modified`() {
173+
val originalEvent = sentryEventConfigurator.originalEvent
174+
val event = sentryEventConfigurator.applyOptions()
175+
assertNotNull(event)
176+
assertEquals(originalEvent.logger, event.logger)
177+
}
178+
179+
@Test
180+
fun `event level is not modified if KMP beforeSend callback config is not modified`() {
181+
val originalEvent = sentryEventConfigurator.originalEvent
182+
val event = sentryEventConfigurator.applyOptions()
183+
assertNotNull(event)
184+
assertEquals(originalEvent.level, event.level)
185+
}
186+
187+
@Test
188+
fun `event message is not modified if KMP beforeSend callback config is not modified`() {
189+
val originalEvent = sentryEventConfigurator.originalEvent
190+
val event = sentryEventConfigurator.applyOptions()
191+
assertNotNull(event)
192+
assertEquals(originalEvent.message, event.message)
193+
}
194+
195+
@Test
196+
fun `event release is not modified if KMP beforeSend callback config is not modified`() {
197+
val originalEvent = sentryEventConfigurator.originalEvent
198+
val event = sentryEventConfigurator.applyOptions()
199+
assertNotNull(event)
200+
assertEquals(originalEvent.release, event.release)
201+
}
202+
203+
@Test
204+
fun `event environment is not modified if KMP beforeSend callback config is not modified`() {
205+
val originalEvent = sentryEventConfigurator.originalEvent
206+
val event = sentryEventConfigurator.applyOptions()
207+
assertNotNull(event)
208+
assertEquals(originalEvent.environment, event.environment)
209+
}
210+
211+
@Test
212+
fun `event serverName is not modified if KMP beforeSend callback config is not modified`() {
213+
val originalEvent = sentryEventConfigurator.originalEvent
214+
val event = sentryEventConfigurator.applyOptions()
215+
assertNotNull(event)
216+
assertEquals(originalEvent.serverName, event.serverName)
217+
}
218+
219+
@Test
220+
fun `event dist is not modified if KMP beforeSend callback config is not modified`() {
221+
val originalEvent = sentryEventConfigurator.originalEvent
222+
val event = sentryEventConfigurator.applyOptions()
223+
assertNotNull(event)
224+
assertEquals(originalEvent.dist, event.dist)
225+
}
226+
227+
@Test
228+
fun `event fingerprint is not modified if KMP beforeSend callback config is not modified`() {
229+
val originalEvent = sentryEventConfigurator.originalEvent
230+
val event = sentryEventConfigurator.applyOptions()
231+
assertNotNull(event)
232+
assertEquals(originalEvent.fingerprint, event.fingerprint)
233+
}
234+
235+
@Test
236+
fun `event tags are not modified if KMP beforeSend callback config is not modified`() {
237+
val originalEvent = sentryEventConfigurator.originalEvent
238+
val event = sentryEventConfigurator.applyOptions()
239+
assertNotNull(event)
240+
assertEquals(originalEvent.tags, event.tags)
241+
}
242+
243+
@Test
244+
fun `event breadcrumbs are not modified if KMP beforeSend callback config is not modified`() {
245+
val originalEvent = sentryEventConfigurator.originalEvent
246+
val event = sentryEventConfigurator.applyOptions()
247+
assertNotNull(event)
248+
assertEquals(originalEvent.breadcrumbs, event.breadcrumbs)
249+
}
250+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package io.sentry.kotlin.multiplatform
2+
3+
/**
4+
* This class deals with configuring and modifying a SentryEvent.
5+
* It is used to test any code that can alter a SentryEvent.
6+
*/
7+
expect class SentryEventConfigurator() {
8+
val originalEvent: SentryEvent
9+
fun applyOptions(optionsConfiguration: OptionsConfiguration): SentryEvent?
10+
fun applyOptions(options: SentryOptions = SentryOptions()): SentryEvent?
11+
}

0 commit comments

Comments
 (0)