@@ -17,6 +17,7 @@ import kotlin.test.assertTrue
1717import org.junit.runner.RunWith
1818import org.mockito.kotlin.any
1919import org.mockito.kotlin.argThat
20+ import org.mockito.kotlin.check
2021import org.mockito.kotlin.spy
2122import org.mockito.kotlin.verify
2223import org.mockito.kotlin.whenever
@@ -118,6 +119,64 @@ class TombstoneIntegrationTest : ApplicationExitIntegrationTestBase<TombstoneHin
118119 )
119120 }
120121
122+ @Test
123+ fun `when merging with native event, uses native event as base with tombstone stack traces` () {
124+ val integration =
125+ fixture.getSut(tmpDir, lastReportedTimestamp = oldTimestamp) { options ->
126+ val outboxDir = File (options.outboxPath!! )
127+ outboxDir.mkdirs()
128+ createNativeEnvelopeWithContext(outboxDir, newTimestamp)
129+ }
130+
131+ // Add tombstone with timestamp matching the native event
132+ fixture.addAppExitInfo(timestamp = newTimestamp)
133+
134+ integration.register(fixture.scopes, fixture.options)
135+
136+ verify(fixture.scopes)
137+ .captureEvent(
138+ check<SentryEvent > { event ->
139+ // Verify native SDK context is preserved
140+ assertEquals(" native-sdk-user-id" , event.user?.id)
141+ assertEquals(" native-sdk-tag-value" , event.getTag(" native-sdk-tag" ))
142+
143+ // Verify tombstone stack trace data is applied
144+ assertNotNull(event.exceptions)
145+ assertTrue(event.exceptions!! .isNotEmpty())
146+ assertEquals(" TombstoneMerged" , event.exceptions!! [0 ].mechanism?.type)
147+
148+ // Verify tombstone debug meta is applied
149+ assertNotNull(event.debugMeta)
150+ assertTrue(event.debugMeta!! .images!! .isNotEmpty())
151+
152+ // Verify tombstone threads are applied (tombstone has 62 threads)
153+ assertEquals(62 , event.threads?.size)
154+ },
155+ any<Hint >(),
156+ )
157+ }
158+
159+ private fun createNativeEnvelopeWithContext (outboxDir : File , timestamp : Long ): File {
160+ val isoTimestamp = DateUtils .getTimestamp(DateUtils .getDateTime(timestamp))
161+
162+ // Native SDK event with user context and tags that should be preserved after merge
163+ val eventJson =
164+ """ {"event_id":"9ec79c33ec9942ab8353589fcb2e04dc","timestamp":"$isoTimestamp ","platform":"native","level":"fatal","user":{"id":"native-sdk-user-id"},"tags":{"native-sdk-tag":"native-sdk-tag-value"}}"""
165+ val eventJsonSize = eventJson.toByteArray(Charsets .UTF_8 ).size
166+
167+ val envelopeContent =
168+ """
169+ {"event_id":"9ec79c33ec9942ab8353589fcb2e04dc"}
170+ {"type":"event","length":$eventJsonSize ,"content_type":"application/json"}
171+ $eventJson
172+ """
173+ .trimIndent()
174+
175+ return File (outboxDir, " native-envelope-with-context.envelope" ).apply {
176+ writeText(envelopeContent)
177+ }
178+ }
179+
121180 private fun createNativeEnvelopeWithAttachment (outboxDir : File , timestamp : Long ): File {
122181 val isoTimestamp = DateUtils .getTimestamp(DateUtils .getDateTime(timestamp))
123182
0 commit comments