Skip to content

Commit 9e1066e

Browse files
committed
added tests
1 parent 3c0a6fb commit 9e1066e

File tree

8 files changed

+266
-69
lines changed

8 files changed

+266
-69
lines changed

sentry/src/test/java/io/sentry/NoOpSentryClientTest.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ class NoOpSentryClientTest {
2929
fun `captureEnvelope returns empty SentryId`() =
3030
assertEquals(SentryId.EMPTY_ID, sut.captureEnvelope(mock()))
3131

32+
@Test
33+
fun `captureFeedback returns empty SentryId`() =
34+
assertEquals(SentryId.EMPTY_ID, sut.captureFeedback(mock(), mock(), mock()))
35+
3236
@Test
3337
fun `close does not affect captureEvent`() {
3438
sut.close()

sentry/src/test/java/io/sentry/SentryClientTest.kt

Lines changed: 190 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -293,59 +293,6 @@ class SentryClientTest {
293293
assertEquals(SentryLevel.DEBUG, sentEvent!!.level)
294294
}
295295

296-
@Test
297-
fun `when captureFeedback is called, sentry event contains feedback in contexts and header type`() {
298-
var sentEvent: SentryEvent? = null
299-
fixture.sentryOptions.setBeforeSend { e, _ -> sentEvent = e; e }
300-
val sut = fixture.getSut()
301-
val scope = createScope()
302-
sut.captureFeedback(Feedback("message"), null, scope)
303-
304-
val sentFeedback = sentEvent!!.contexts.feedback
305-
assertNotNull(sentFeedback)
306-
assertEquals("message", sentFeedback.message)
307-
assertNull(sentFeedback.replayId)
308-
assertNull(sentFeedback.url)
309-
310-
verify(fixture.transport).send(
311-
check {
312-
assertEquals(SentryItemType.Feedback, it.items.first().header.type)
313-
},
314-
anyOrNull()
315-
)
316-
}
317-
318-
@Test
319-
fun `when captureFeedback, scope replay id is attached to feedback`() {
320-
var sentEvent: SentryEvent? = null
321-
fixture.sentryOptions.setBeforeSend { e, _ -> sentEvent = e; e }
322-
val replayId = SentryId()
323-
val sut = fixture.getSut()
324-
val scope = createScope()
325-
scope.replayId = replayId
326-
sut.captureFeedback(Feedback("message"), null, scope)
327-
328-
val sentFeedback = sentEvent!!.contexts.feedback
329-
assertNotNull(sentFeedback)
330-
assertEquals(replayId.toString(), sentFeedback.replayId?.toString())
331-
assertNull(sentFeedback.url)
332-
}
333-
334-
@Test
335-
fun `when captureFeedback, screen is attached to feedback as url`() {
336-
var sentEvent: SentryEvent? = null
337-
fixture.sentryOptions.setBeforeSend { e, _ -> sentEvent = e; e }
338-
val sut = fixture.getSut()
339-
val scope = createScope()
340-
scope.screen = "screen"
341-
sut.captureFeedback(Feedback("message"), null, scope)
342-
343-
val sentFeedback = sentEvent!!.contexts.feedback
344-
assertNotNull(sentFeedback)
345-
assertEquals("screen", sentFeedback.url)
346-
assertNull(sentFeedback.replayId)
347-
}
348-
349296
@Test
350297
fun `when event has release, value from options not applied`() {
351298
val event = SentryEvent()
@@ -2804,6 +2751,8 @@ class SentryClientTest {
28042751
verify(fixture.transport).send(anyOrNull(), anyOrNull())
28052752
}
28062753

2754+
//region Replay
2755+
28072756
@Test
28082757
fun `when captureReplayEvent, envelope is sent`() {
28092758
val sut = fixture.getSut()
@@ -3044,6 +2993,194 @@ class SentryClientTest {
30442993
)
30452994
}
30462995

2996+
//endregion
2997+
2998+
//region Feedback
2999+
3000+
@Test
3001+
fun `when captureFeedback is called, sentry event contains feedback in contexts and header type`() {
3002+
var sentEvent: SentryEvent? = null
3003+
fixture.sentryOptions.setBeforeSendFeedback { e, _ -> sentEvent = e; e }
3004+
val sut = fixture.getSut()
3005+
val scope = createScope()
3006+
sut.captureFeedback(Feedback("message"), null, scope)
3007+
3008+
val sentFeedback = sentEvent!!.contexts.feedback
3009+
assertNotNull(sentFeedback)
3010+
assertEquals("message", sentFeedback.message)
3011+
assertNull(sentFeedback.replayId)
3012+
assertNull(sentFeedback.url)
3013+
3014+
verify(fixture.transport).send(
3015+
check {
3016+
assertEquals(SentryItemType.Feedback, it.items.first().header.type)
3017+
},
3018+
anyOrNull()
3019+
)
3020+
}
3021+
3022+
@Test
3023+
fun `when captureFeedback, scope data is attached to feedback`() {
3024+
var sentEvent: SentryEvent? = null
3025+
fixture.sentryOptions.setBeforeSendFeedback { e, _ -> sentEvent = e; e }
3026+
val sut = fixture.getSut()
3027+
val scope = createScope()
3028+
val scopeReplayId = SentryId()
3029+
scope.contexts.setTrace(SpanContext("test"))
3030+
scope.setContexts("context-key", "context-value")
3031+
scope.screen = "screen"
3032+
scope.replayId = scopeReplayId
3033+
sut.captureFeedback(Feedback("message"), null, scope)
3034+
3035+
val sentFeedback = sentEvent!!.contexts.feedback
3036+
assertNotNull(sentFeedback)
3037+
// User, tags and contexts are applied to the feedback
3038+
assertEquals(scope.user, sentEvent!!.user)
3039+
assertEquals("tags", sentEvent!!.tags!!["tags"])
3040+
assertEquals(
3041+
scope.contexts.trace!!.traceId.toString(),
3042+
sentEvent!!.contexts.trace!!.traceId.toString()
3043+
)
3044+
assertEquals(mapOf("value" to "context-value"), sentEvent!!.contexts["context-key"])
3045+
// currently running replay id set in scope is applied to feedback
3046+
assertEquals(scopeReplayId, sentFeedback.replayId)
3047+
// screen set to scope is applied as url
3048+
assertEquals("screen", sentFeedback.url)
3049+
// extras and breadcrumbs are not applied to feedback
3050+
assertNull(sentEvent!!.extras)
3051+
assertNull(sentEvent!!.breadcrumbs)
3052+
}
3053+
3054+
@Test
3055+
fun `when captureFeedback, replay controller is stopped if no replay id is provided`() {
3056+
var sentEvent: SentryEvent? = null
3057+
fixture.sentryOptions.setBeforeSendFeedback { e, _ -> sentEvent = e; e }
3058+
val replayController = mock<ReplayController>()
3059+
val replayId = SentryId()
3060+
val scope = createScope()
3061+
whenever(replayController.captureReplay(any())).thenAnswer {
3062+
run { scope.replayId = replayId }
3063+
}
3064+
val sut = fixture.getSut { it.setReplayController(replayController) }
3065+
// When there is no replay id in the feedback
3066+
sut.captureFeedback(Feedback("message"), null, scope)
3067+
3068+
// Then the replay controller captures the replay
3069+
verify(replayController).captureReplay(eq(false))
3070+
3071+
val sentFeedback = sentEvent!!.contexts.feedback
3072+
assertNotNull(sentFeedback)
3073+
// And the replay id is set to the one from the scope (coming from the replay controller)
3074+
assertEquals(replayId, sentFeedback.replayId)
3075+
}
3076+
3077+
@Test
3078+
fun `when captureFeedback, replay controller is not stopped if replay id is provided`() {
3079+
var sentEvent: SentryEvent? = null
3080+
fixture.sentryOptions.setBeforeSendFeedback { e, _ -> sentEvent = e; e }
3081+
val replayController = mock<ReplayController>()
3082+
val replayId = SentryId()
3083+
val scope = createScope()
3084+
whenever(replayController.captureReplay(any())).thenAnswer {
3085+
run { scope.replayId = replayId }
3086+
}
3087+
val sut = fixture.getSut { it.setReplayController(replayController) }
3088+
// When there is replay id in the feedback
3089+
val feedback = Feedback("message")
3090+
feedback.setReplayId(SentryId())
3091+
sut.captureFeedback(feedback, null, scope)
3092+
3093+
// Then the replay controller doesn't capture the replay
3094+
verify(replayController, never()).captureReplay(any())
3095+
3096+
val sentFeedback = sentEvent!!.contexts.feedback
3097+
assertNotNull(sentFeedback)
3098+
// And the replay id is set to the one from the scope (coming from the replay controller)
3099+
assertNotNull(sentFeedback.replayId)
3100+
assertNotEquals(replayId, sentFeedback.replayId)
3101+
}
3102+
3103+
@Test
3104+
fun `when beforeSendFeedback is set, callback is invoked`() {
3105+
var invoked = false
3106+
fixture.sentryOptions.setBeforeSendFeedback { event: SentryEvent, _: Hint -> invoked = true; event }
3107+
fixture.getSut().captureFeedback(Feedback("message"), null, createScope())
3108+
assertTrue(invoked)
3109+
}
3110+
3111+
@Test
3112+
fun `when beforeSendFeedback returns null, feedback is dropped`() {
3113+
fixture.sentryOptions.setBeforeSendFeedback { event: SentryEvent, _: Hint -> null }
3114+
fixture.getSut().captureFeedback(Feedback("message"), null, createScope())
3115+
verify(fixture.transport, never()).send(any(), anyOrNull())
3116+
3117+
assertClientReport(
3118+
fixture.sentryOptions.clientReportRecorder,
3119+
listOf(
3120+
DiscardedEvent(DiscardReason.BEFORE_SEND.reason, DataCategory.Feedback.category, 1)
3121+
)
3122+
)
3123+
}
3124+
3125+
@Test
3126+
fun `when beforeSendFeedback returns new instance, new instance is sent`() {
3127+
val expected = SentryEvent().apply { contexts.setFeedback(Feedback("expected")) }
3128+
fixture.sentryOptions.setBeforeSendFeedback { _, _ -> expected }
3129+
3130+
fixture.getSut().captureFeedback(Feedback("sent"), null, Scope(fixture.sentryOptions))
3131+
3132+
verify(fixture.transport).send(
3133+
check {
3134+
val event = getEventFromData(it.items.first().data)
3135+
assertEquals("expected", event.contexts.feedback!!.message)
3136+
},
3137+
anyOrNull()
3138+
)
3139+
verifyNoMoreInteractions(fixture.transport)
3140+
}
3141+
3142+
@Test
3143+
fun `when beforeSendFeedback throws an exception, feedback is dropped`() {
3144+
val exception = Exception("test")
3145+
fixture.sentryOptions.setBeforeSendFeedback { _, _ -> throw exception }
3146+
val id = fixture.getSut().captureFeedback(Feedback("message"), null, Scope(fixture.sentryOptions))
3147+
assertEquals(SentryId.EMPTY_ID, id)
3148+
3149+
assertClientReport(
3150+
fixture.sentryOptions.clientReportRecorder,
3151+
listOf(
3152+
DiscardedEvent(DiscardReason.BEFORE_SEND.reason, DataCategory.Feedback.category, 1)
3153+
)
3154+
)
3155+
}
3156+
3157+
@Test
3158+
fun `when feedback is dropped, captures client report with datacategory feedback`() {
3159+
fixture.sentryOptions.addEventProcessor(DropEverythingEventProcessor())
3160+
val sut = fixture.getSut()
3161+
sut.captureFeedback(Feedback("message"), null, createScope())
3162+
3163+
assertClientReport(
3164+
fixture.sentryOptions.clientReportRecorder,
3165+
listOf(DiscardedEvent(DiscardReason.EVENT_PROCESSOR.reason, DataCategory.Feedback.category, 1))
3166+
)
3167+
}
3168+
3169+
@Test
3170+
fun `captureFeedback does not capture replay when backfilled`() {
3171+
val replayController = mock<ReplayController>()
3172+
val sut = fixture.getSut { it.setReplayController(replayController) }
3173+
3174+
sut.captureFeedback(
3175+
Feedback("message"),
3176+
HintUtils.createWithTypeCheckHint(BackfillableHint()),
3177+
createScope()
3178+
)
3179+
verify(replayController, never()).captureReplay(any())
3180+
}
3181+
3182+
//endregion
3183+
30473184
private fun givenScopeWithStartedSession(errored: Boolean = false, crashed: Boolean = false): IScope {
30483185
val scope = createScope(fixture.sentryOptions)
30493186
scope.startSession()

sentry/src/test/java/io/sentry/SentryTest.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -972,9 +972,19 @@ class SentryTest {
972972

973973
Sentry.captureFeedback(feedback)
974974
Sentry.captureFeedback(feedback, hint)
975+
Sentry.captureFeedback(feedback, hint) { it.setTag("testKey", "testValue") }
975976

976977
verify(client).captureFeedback(eq(feedback), eq(null), anyOrNull())
977-
verify(client).captureFeedback(eq(feedback), eq(hint), anyOrNull())
978+
verify(client).captureFeedback(
979+
eq(feedback),
980+
eq(hint),
981+
check { assertFalse(it.tags.containsKey("testKey")) }
982+
)
983+
verify(client).captureFeedback(
984+
eq(feedback),
985+
eq(hint),
986+
check { assertEquals("testValue", it.tags["testKey"]) }
987+
)
978988
}
979989

980990
@Test

sentry/src/test/java/io/sentry/clientreport/ClientReportTest.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import io.sentry.UncaughtExceptionHandlerIntegration.UncaughtExceptionHint
2626
import io.sentry.UserFeedback
2727
import io.sentry.dsnString
2828
import io.sentry.hints.Retryable
29+
import io.sentry.protocol.Feedback
2930
import io.sentry.protocol.SentryId
3031
import io.sentry.protocol.SentryTransaction
3132
import io.sentry.protocol.User
@@ -54,6 +55,7 @@ class ClientReportTest {
5455
val scopes = mock<IScopes>()
5556
whenever(scopes.options).thenReturn(opts)
5657
val transaction = SentryTracer(TransactionContext("name", "op"), scopes)
58+
val feedbackEvent = SentryEvent().apply { contexts.setFeedback(Feedback("message")) }
5759

5860
val lostClientReport = ClientReport(
5961
DateUtils.getCurrentDateTime(),
@@ -73,13 +75,14 @@ class ClientReportTest {
7375
SentryEnvelopeItem.fromAttachment(opts.serializer, NoOpLogger.getInstance(), Attachment("{ \"number\": 10 }".toByteArray(), "log.json"), 1000),
7476
SentryEnvelopeItem.fromProfilingTrace(ProfilingTraceData(File(""), transaction), 1000, opts.serializer),
7577
SentryEnvelopeItem.fromCheckIn(opts.serializer, CheckIn("monitor-slug-1", CheckInStatus.ERROR)),
76-
SentryEnvelopeItem.fromReplay(opts.serializer, opts.logger, SentryReplayEvent(), ReplayRecording(), false)
78+
SentryEnvelopeItem.fromReplay(opts.serializer, opts.logger, SentryReplayEvent(), ReplayRecording(), false),
79+
SentryEnvelopeItem.fromEvent(opts.serializer, feedbackEvent)
7780
)
7881

7982
clientReportRecorder.recordLostEnvelope(DiscardReason.NETWORK_ERROR, envelope)
8083

8184
val clientReportAtEnd = clientReportRecorder.resetCountsAndGenerateClientReport()
82-
testHelper.assertTotalCount(15, clientReportAtEnd)
85+
testHelper.assertTotalCount(16, clientReportAtEnd)
8386
testHelper.assertCountFor(DiscardReason.SAMPLE_RATE, DataCategory.Error, 3, clientReportAtEnd)
8487
testHelper.assertCountFor(DiscardReason.BEFORE_SEND, DataCategory.Error, 2, clientReportAtEnd)
8588
testHelper.assertCountFor(DiscardReason.QUEUE_OVERFLOW, DataCategory.Transaction, 1, clientReportAtEnd)
@@ -92,6 +95,7 @@ class ClientReportTest {
9295
testHelper.assertCountFor(DiscardReason.NETWORK_ERROR, DataCategory.Profile, 1, clientReportAtEnd)
9396
testHelper.assertCountFor(DiscardReason.NETWORK_ERROR, DataCategory.Monitor, 1, clientReportAtEnd)
9497
testHelper.assertCountFor(DiscardReason.NETWORK_ERROR, DataCategory.Replay, 1, clientReportAtEnd)
98+
testHelper.assertCountFor(DiscardReason.NETWORK_ERROR, DataCategory.Feedback, 1, clientReportAtEnd)
9599
}
96100

97101
@Test
@@ -136,7 +140,7 @@ class ClientReportTest {
136140
DateUtils.getCurrentDateTime(),
137141
listOf(
138142
DiscardedEvent(DiscardReason.SAMPLE_RATE.reason, DataCategory.Error.category, 3),
139-
DiscardedEvent(DiscardReason.BEFORE_SEND.reason, DataCategory.Error.category, 2),
143+
DiscardedEvent(DiscardReason.BEFORE_SEND.reason, DataCategory.Feedback.category, 2),
140144
DiscardedEvent(DiscardReason.QUEUE_OVERFLOW.reason, DataCategory.Transaction.category, 1),
141145
DiscardedEvent(DiscardReason.SAMPLE_RATE.reason, DataCategory.Profile.category, 2)
142146
)
@@ -149,7 +153,7 @@ class ClientReportTest {
149153
val clientReportAtEnd = clientReportRecorder.resetCountsAndGenerateClientReport()
150154
testHelper.assertTotalCount(8, clientReportAtEnd)
151155
testHelper.assertCountFor(DiscardReason.SAMPLE_RATE, DataCategory.Error, 3, clientReportAtEnd)
152-
testHelper.assertCountFor(DiscardReason.BEFORE_SEND, DataCategory.Error, 2, clientReportAtEnd)
156+
testHelper.assertCountFor(DiscardReason.BEFORE_SEND, DataCategory.Feedback, 2, clientReportAtEnd)
153157
testHelper.assertCountFor(DiscardReason.QUEUE_OVERFLOW, DataCategory.Transaction, 1, clientReportAtEnd)
154158
testHelper.assertCountFor(DiscardReason.SAMPLE_RATE, DataCategory.Profile, 2, clientReportAtEnd)
155159
}

sentry/src/test/java/io/sentry/protocol/ContextsSerializationTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class ContextsSerializationTest {
2121
setOperatingSystem(OperatingSystemSerializationTest.Fixture().getSut())
2222
setRuntime(SentryRuntimeSerializationTest.Fixture().getSut())
2323
setGpu(GpuSerializationTest.Fixture().getSut())
24+
setFeedback(FeedbackTest.Fixture().getSut())
2425
setResponse(ResponseSerializationTest.Fixture().getSut())
2526
setTrace(SpanContextSerializationTest.Fixture().getSut())
2627
setSpring(SpringSerializationTest.Fixture().getSut())

0 commit comments

Comments
 (0)