@@ -39,6 +39,7 @@ import java.util.concurrent.atomic.AtomicReference
39
39
import kotlin.test.BeforeTest
40
40
import kotlin.test.Test
41
41
import kotlin.test.assertEquals
42
+ import kotlin.test.assertNotEquals
42
43
import kotlin.test.assertNotNull
43
44
import kotlin.test.assertNull
44
45
import kotlin.test.assertTrue
@@ -84,7 +85,7 @@ class InternalSentrySdkTest {
84
85
capturedEnvelopes.clear()
85
86
}
86
87
87
- fun captureEnvelopeWithEvent (event : SentryEvent = SentryEvent ()) {
88
+ fun captureEnvelopeWithEvent (event : SentryEvent = SentryEvent (), maybeStartNewSession : Boolean = false ) {
88
89
// create an envelope with session data
89
90
val options = Sentry .getCurrentHub().options
90
91
val eventId = SentryId ()
@@ -103,7 +104,24 @@ class InternalSentrySdkTest {
103
104
options.serializer.serialize(envelope, outputStream)
104
105
val data = outputStream.toByteArray()
105
106
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
+ }
107
125
}
108
126
109
127
fun mockFinishedAppStart () {
@@ -313,7 +331,7 @@ class InternalSentrySdkTest {
313
331
314
332
@Test
315
333
fun `captureEnvelope fails if payload is invalid` () {
316
- assertNull(InternalSentrySdk .captureEnvelope(ByteArray (8 )))
334
+ assertNull(InternalSentrySdk .captureEnvelope(ByteArray (8 ), false ))
317
335
}
318
336
319
337
@Test
@@ -337,27 +355,19 @@ class InternalSentrySdkTest {
337
355
}
338
356
339
357
@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 ` () {
341
359
val fixture = Fixture ()
342
360
fixture.init (context)
343
361
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
+ }
349
368
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())
361
371
362
372
val capturedEnvelope = fixture.capturedEnvelopes.first()
363
373
val capturedEnvelopeItems = capturedEnvelope.items.toList()
@@ -374,12 +384,52 @@ class InternalSentrySdkTest {
374
384
)!!
375
385
assertEquals(Session .State .Crashed , capturedSession.status)
376
386
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
+
378
399
val scopeRef = AtomicReference <IScope >()
379
400
Sentry .configureScope { scope ->
380
401
scopeRef.set(scope)
381
402
}
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)
383
433
}
384
434
385
435
@Test
0 commit comments