@@ -39,6 +39,7 @@ import java.util.concurrent.atomic.AtomicReference
3939import kotlin.test.BeforeTest
4040import kotlin.test.Test
4141import kotlin.test.assertEquals
42+ import kotlin.test.assertNotEquals
4243import kotlin.test.assertNotNull
4344import kotlin.test.assertNull
4445import kotlin.test.assertTrue
@@ -84,7 +85,7 @@ class InternalSentrySdkTest {
8485 capturedEnvelopes.clear()
8586 }
8687
87- fun captureEnvelopeWithEvent (event : SentryEvent = SentryEvent ()) {
88+ fun captureEnvelopeWithEvent (event : SentryEvent = SentryEvent (), maybeStartNewSession : Boolean = false ) {
8889 // create an envelope with session data
8990 val options = Sentry .getCurrentHub().options
9091 val eventId = SentryId ()
@@ -103,7 +104,24 @@ class InternalSentrySdkTest {
103104 options.serializer.serialize(envelope, outputStream)
104105 val data = outputStream.toByteArray()
105106
106- InternalSentrySdk .captureEnvelope(data)
107+ InternalSentrySdk .captureEnvelope(data, maybeStartNewSession)
108+ }
109+
110+ fun createSentryEventWithUnhandledException (): SentryEvent {
111+ return SentryEvent (RuntimeException ()).apply {
112+ val mechanism = Mechanism ()
113+ mechanism.isHandled = false
114+
115+ val factory = SentryExceptionFactory (mock())
116+ val sentryExceptions = factory.getSentryExceptions(
117+ ExceptionMechanismException (
118+ mechanism,
119+ Throwable (),
120+ Thread ()
121+ )
122+ )
123+ exceptions = sentryExceptions
124+ }
107125 }
108126
109127 fun mockFinishedAppStart () {
@@ -313,7 +331,7 @@ class InternalSentrySdkTest {
313331
314332 @Test
315333 fun `captureEnvelope fails if payload is invalid` () {
316- assertNull(InternalSentrySdk .captureEnvelope(ByteArray (8 )))
334+ assertNull(InternalSentrySdk .captureEnvelope(ByteArray (8 ), false ))
317335 }
318336
319337 @Test
@@ -337,27 +355,19 @@ class InternalSentrySdkTest {
337355 }
338356
339357 @Test
340- fun `captureEnvelope correctly enriches the envelope with session data` () {
358+ fun `captureEnvelope correctly enriches the envelope with session data and does not start new session ` () {
341359 val fixture = Fixture ()
342360 fixture.init (context)
343361
344- // when capture envelope is called with an crashed event
345- fixture.captureEnvelopeWithEvent(
346- SentryEvent (RuntimeException ()).apply {
347- val mechanism = Mechanism ()
348- mechanism.isHandled = false
362+ // keep reference for current session for later assertions
363+ // we need to get the reference now as it will be removed from the scope
364+ val sessionRef = AtomicReference <Session >()
365+ Sentry .configureScope { scope ->
366+ sessionRef.set(scope.session)
367+ }
349368
350- val factory = SentryExceptionFactory (mock())
351- val sentryExceptions = factory.getSentryExceptions(
352- ExceptionMechanismException (
353- mechanism,
354- Throwable (),
355- Thread ()
356- )
357- )
358- exceptions = sentryExceptions
359- }
360- )
369+ // when capture envelope is called with an crashed event
370+ fixture.captureEnvelopeWithEvent(fixture.createSentryEventWithUnhandledException())
361371
362372 val capturedEnvelope = fixture.capturedEnvelopes.first()
363373 val capturedEnvelopeItems = capturedEnvelope.items.toList()
@@ -374,12 +384,52 @@ class InternalSentrySdkTest {
374384 )!!
375385 assertEquals(Session .State .Crashed , capturedSession.status)
376386
377- // and the local session should be marked as crashed too
387+ assertEquals(Session .State .Crashed , sessionRef.get().status)
388+ assertEquals(capturedSession.sessionId, sessionRef.get().sessionId)
389+ }
390+
391+ @Test
392+ fun `captureEnvelope starts new session when enabled` () {
393+ val fixture = Fixture ()
394+ fixture.init (context)
395+
396+ // when capture envelope is called with an crashed event
397+ fixture.captureEnvelopeWithEvent(fixture.createSentryEventWithUnhandledException(), true )
398+
378399 val scopeRef = AtomicReference <IScope >()
379400 Sentry .configureScope { scope ->
380401 scopeRef.set(scope)
381402 }
382- assertEquals(Session .State .Crashed , scopeRef.get().session!! .status)
403+
404+ // first envelope is the new session start
405+ val capturedStartSessionEnvelope = fixture.capturedEnvelopes.first()
406+ val capturedNewSessionStart = fixture.options.serializer.deserialize(
407+ InputStreamReader (ByteArrayInputStream (capturedStartSessionEnvelope.items.toList()[0 ].data)),
408+ Session ::class .java
409+ )!!
410+ assertEquals(capturedNewSessionStart.sessionId, scopeRef.get().session!! .sessionId)
411+ assertEquals(Session .State .Ok , capturedNewSessionStart.status)
412+
413+ val capturedEnvelope = fixture.capturedEnvelopes.last()
414+ val capturedEnvelopeItems = capturedEnvelope.items.toList()
415+
416+ // there should be two envelopes session start and captured crash
417+ assertEquals(2 , fixture.capturedEnvelopes.size)
418+
419+ // then it should contain the original event + session
420+ assertEquals(2 , capturedEnvelopeItems.size)
421+ assertEquals(SentryItemType .Event , capturedEnvelopeItems[0 ].header.type)
422+ assertEquals(SentryItemType .Session , capturedEnvelopeItems[1 ].header.type)
423+
424+ // and then the sent session should be marked as crashed
425+ val capturedSession = fixture.options.serializer.deserialize(
426+ InputStreamReader (ByteArrayInputStream (capturedEnvelopeItems[1 ].data)),
427+ Session ::class .java
428+ )!!
429+ assertEquals(Session .State .Crashed , capturedSession.status)
430+
431+ // and the local session should be a new session
432+ assertNotEquals(capturedSession.sessionId, scopeRef.get().session!! .sessionId)
383433 }
384434
385435 @Test
0 commit comments