Skip to content

Commit dd2d6a8

Browse files
committed
added tests
1 parent 813ff1d commit dd2d6a8

File tree

13 files changed

+298
-1
lines changed

13 files changed

+298
-1
lines changed

sentry/api/sentry.api

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,8 @@ public final class io/sentry/HubAdapter : io/sentry/IHub {
584584
public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/Hint;Lio/sentry/ScopeCallback;)Lio/sentry/protocol/SentryId;
585585
public fun captureException (Ljava/lang/Throwable;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
586586
public fun captureException (Ljava/lang/Throwable;Lio/sentry/Hint;Lio/sentry/ScopeCallback;)Lio/sentry/protocol/SentryId;
587+
public fun captureFeedback (Lio/sentry/protocol/Feedback;)Lio/sentry/protocol/SentryId;
588+
public fun captureFeedback (Lio/sentry/protocol/Feedback;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
587589
public fun captureFeedback (Lio/sentry/protocol/Feedback;Lio/sentry/Hint;Lio/sentry/ScopeCallback;)Lio/sentry/protocol/SentryId;
588590
public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId;
589591
public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;Lio/sentry/ScopeCallback;)Lio/sentry/protocol/SentryId;
@@ -2231,6 +2233,8 @@ public final class io/sentry/ScopesAdapter : io/sentry/IScopes {
22312233
public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/Hint;Lio/sentry/ScopeCallback;)Lio/sentry/protocol/SentryId;
22322234
public fun captureException (Ljava/lang/Throwable;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
22332235
public fun captureException (Ljava/lang/Throwable;Lio/sentry/Hint;Lio/sentry/ScopeCallback;)Lio/sentry/protocol/SentryId;
2236+
public fun captureFeedback (Lio/sentry/protocol/Feedback;)Lio/sentry/protocol/SentryId;
2237+
public fun captureFeedback (Lio/sentry/protocol/Feedback;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
22342238
public fun captureFeedback (Lio/sentry/protocol/Feedback;Lio/sentry/Hint;Lio/sentry/ScopeCallback;)Lio/sentry/protocol/SentryId;
22352239
public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId;
22362240
public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;Lio/sentry/ScopeCallback;)Lio/sentry/protocol/SentryId;
@@ -4747,13 +4751,15 @@ public final class io/sentry/protocol/Feedback : io/sentry/JsonSerializable, io/
47474751
public static final field TYPE Ljava/lang/String;
47484752
public fun <init> (Lio/sentry/protocol/Feedback;)V
47494753
public fun <init> (Ljava/lang/String;)V
4754+
public fun equals (Ljava/lang/Object;)Z
47504755
public fun getAssociatedEventId ()Lio/sentry/protocol/SentryId;
47514756
public fun getContactEmail ()Ljava/lang/String;
47524757
public fun getMessage ()Ljava/lang/String;
47534758
public fun getName ()Ljava/lang/String;
47544759
public fun getReplayId ()Lio/sentry/protocol/SentryId;
47554760
public fun getUnknown ()Ljava/util/Map;
47564761
public fun getUrl ()Ljava/lang/String;
4762+
public fun hashCode ()I
47574763
public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V
47584764
public fun setAssociatedEventId (Lio/sentry/protocol/SentryId;)V
47594765
public fun setContactEmail (Ljava/lang/String;)V

sentry/src/main/java/io/sentry/HubAdapter.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ public boolean isEnabled() {
5151
return Sentry.captureMessage(message, level, callback);
5252
}
5353

54+
@Override
55+
public @NotNull SentryId captureFeedback(@NotNull Feedback feedback) {
56+
return Sentry.captureFeedback(feedback);
57+
}
58+
59+
@Override
60+
public @NotNull SentryId captureFeedback(@NotNull Feedback feedback, @Nullable Hint hint) {
61+
return Sentry.captureFeedback(feedback, hint);
62+
}
63+
5464
@Override
5565
public @NotNull SentryId captureFeedback(
5666
@NotNull Feedback feedback, @Nullable Hint hint, @Nullable ScopeCallback callback) {

sentry/src/main/java/io/sentry/ScopesAdapter.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ public boolean isEnabled() {
4747
return Sentry.captureMessage(message, level, callback);
4848
}
4949

50+
@Override
51+
public @NotNull SentryId captureFeedback(@NotNull Feedback feedback) {
52+
return Sentry.captureFeedback(feedback);
53+
}
54+
55+
@Override
56+
public @NotNull SentryId captureFeedback(@NotNull Feedback feedback, @Nullable Hint hint) {
57+
return Sentry.captureFeedback(feedback, hint);
58+
}
59+
5060
@Override
5161
public @NotNull SentryId captureFeedback(
5262
@NotNull Feedback feedback, @Nullable Hint hint, @Nullable ScopeCallback callback) {

sentry/src/main/java/io/sentry/protocol/Feedback.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
import io.sentry.ObjectReader;
88
import io.sentry.ObjectWriter;
99
import io.sentry.SentryLevel;
10+
import io.sentry.util.CollectionUtils;
1011
import io.sentry.vendor.gson.stream.JsonToken;
1112
import java.io.IOException;
1213
import java.util.HashMap;
1314
import java.util.Map;
15+
import java.util.Objects;
1416
import org.jetbrains.annotations.NotNull;
1517
import org.jetbrains.annotations.Nullable;
1618

@@ -39,7 +41,7 @@ public Feedback(final @NotNull Feedback feedback) {
3941
this.associatedEventId = feedback.associatedEventId;
4042
this.replayId = feedback.replayId;
4143
this.url = feedback.url;
42-
this.unknown = feedback.unknown;
44+
this.unknown = CollectionUtils.newConcurrentHashMap(feedback.unknown);
4345
}
4446

4547
public @Nullable String getContactEmail() {
@@ -90,6 +92,25 @@ public void setMessage(final @NotNull String message) {
9092
this.message = message;
9193
}
9294

95+
@Override
96+
public boolean equals(Object o) {
97+
if (this == o) return true;
98+
if (!(o instanceof Feedback)) return false;
99+
Feedback feedback = (Feedback) o;
100+
return Objects.equals(message, feedback.message)
101+
&& Objects.equals(contactEmail, feedback.contactEmail)
102+
&& Objects.equals(name, feedback.name)
103+
&& Objects.equals(associatedEventId, feedback.associatedEventId)
104+
&& Objects.equals(replayId, feedback.replayId)
105+
&& Objects.equals(url, feedback.url)
106+
&& Objects.equals(unknown, feedback.unknown);
107+
}
108+
109+
@Override
110+
public int hashCode() {
111+
return Objects.hash(message, contactEmail, name, associatedEventId, replayId, url, unknown);
112+
}
113+
93114
// JsonKeys
94115

95116
public static final class JsonKeys {

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.sentry
22

3+
import io.sentry.protocol.Feedback
34
import io.sentry.protocol.SentryTransaction
45
import io.sentry.protocol.User
56
import io.sentry.test.createSentryClientMock
@@ -57,6 +58,20 @@ class HubAdapterTest {
5758
verify(scopes).captureMessage(eq("message"), eq(sentryLevel), eq(scopeCallback))
5859
}
5960

61+
@Test fun `captureFeedback calls Hub`() {
62+
val hint = Hint()
63+
val scopeCallback = mock<ScopeCallback>()
64+
val feedback = Feedback("message")
65+
HubAdapter.getInstance().captureFeedback(feedback)
66+
verify(scopes).captureFeedback(eq(feedback))
67+
68+
HubAdapter.getInstance().captureFeedback(feedback, hint)
69+
verify(scopes).captureFeedback(eq(feedback), eq(hint))
70+
71+
HubAdapter.getInstance().captureFeedback(feedback, hint, scopeCallback)
72+
verify(scopes).captureFeedback(eq(feedback), eq(hint), eq(scopeCallback))
73+
}
74+
6075
@Test fun `captureEnvelope calls Hub`() {
6176
val envelope = mock<SentryEnvelope>()
6277
val hint = mock<Hint>()

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package io.sentry
33
import io.sentry.profilemeasurements.ProfileMeasurement
44
import io.sentry.profilemeasurements.ProfileMeasurementValue
55
import io.sentry.protocol.Device
6+
import io.sentry.protocol.Feedback
67
import io.sentry.protocol.ReplayRecordingSerializationTest
78
import io.sentry.protocol.Request
89
import io.sentry.protocol.SdkVersion
@@ -1245,6 +1246,42 @@ class JsonSerializerTest {
12451246
)
12461247
}
12471248

1249+
@Test
1250+
fun `serializes feedback`() {
1251+
val replayId = SentryId("00000000-0000-0000-0000-000000000001")
1252+
val eventId = SentryId("00000000-0000-0000-0000-000000000002")
1253+
val feedback = Feedback("message")
1254+
feedback.name = "name"
1255+
feedback.contactEmail = "email"
1256+
feedback.url = "url"
1257+
feedback.setReplayId(replayId)
1258+
feedback.setAssociatedEventId(eventId)
1259+
val actual = serializeToString(feedback)
1260+
val expected = "{\"message\":\"message\",\"contact_email\":\"email\",\"name\":\"name\",\"associated_event_id\":\"00000000000000000000000000000002\",\"replay_id\":\"00000000000000000000000000000001\",\"url\":\"url\"}"
1261+
assertEquals(expected, actual)
1262+
}
1263+
1264+
@Test
1265+
fun `deserializes feedback`() {
1266+
val json = """{
1267+
"message":"message",
1268+
"contact_email":"email",
1269+
"name":"name",
1270+
"associated_event_id":"00000000000000000000000000000002",
1271+
"replay_id":"00000000000000000000000000000001",
1272+
"url":"url"
1273+
}"""
1274+
val feedback = fixture.serializer.deserialize(StringReader(json), Feedback::class.java)
1275+
val expected = Feedback("message").apply {
1276+
name = "name"
1277+
contactEmail = "email"
1278+
url = "url"
1279+
setReplayId(SentryId("00000000-0000-0000-0000-000000000001"))
1280+
setAssociatedEventId(SentryId("00000000-0000-0000-0000-000000000002"))
1281+
}
1282+
assertEquals(expected, feedback)
1283+
}
1284+
12481285
@Test
12491286
fun `ser deser replay data`() {
12501287
val replayEvent = SentryReplayEventSerializationTest.Fixture().getSut()

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ class NoOpHubTest {
3939
fun `captureMessage returns empty SentryId`() =
4040
assertEquals(SentryId.EMPTY_ID, sut.captureMessage("message"))
4141

42+
@Test
43+
fun `captureFeedback returns empty SentryId`() =
44+
assertEquals(SentryId.EMPTY_ID, sut.captureFeedback(mock()))
45+
4246
@Test
4347
fun `close does not affect captureEvent`() {
4448
sut.close()

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.sentry
22

3+
import io.sentry.protocol.Feedback
34
import io.sentry.protocol.SentryTransaction
45
import io.sentry.protocol.User
56
import io.sentry.test.createSentryClientMock
@@ -57,6 +58,20 @@ class ScopesAdapterTest {
5758
verify(scopes).captureMessage(eq("message"), eq(sentryLevel), eq(scopeCallback))
5859
}
5960

61+
@Test fun `captureFeedback calls Scopes`() {
62+
val scopeCallback = mock<ScopeCallback>()
63+
val hint = mock<Hint>()
64+
val feedback = Feedback("message")
65+
ScopesAdapter.getInstance().captureFeedback(feedback)
66+
verify(scopes).captureFeedback(eq(feedback))
67+
68+
ScopesAdapter.getInstance().captureFeedback(feedback, hint)
69+
verify(scopes).captureFeedback(eq(feedback), eq(hint))
70+
71+
ScopesAdapter.getInstance().captureFeedback(feedback, hint, scopeCallback)
72+
verify(scopes).captureFeedback(eq(feedback), eq(hint), eq(scopeCallback))
73+
}
74+
6075
@Test fun `captureEnvelope calls Scopes`() {
6176
val envelope = mock<SentryEnvelope>()
6277
val hint = mock<Hint>()

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

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import io.sentry.clientreport.DiscardReason
77
import io.sentry.clientreport.DiscardedEvent
88
import io.sentry.hints.SessionEndHint
99
import io.sentry.hints.SessionStartHint
10+
import io.sentry.protocol.Feedback
1011
import io.sentry.protocol.SentryId
1112
import io.sentry.protocol.SentryTransaction
1213
import io.sentry.protocol.User
@@ -606,6 +607,100 @@ class ScopesTest {
606607

607608
//endregion
608609

610+
//region captureFeedback tests
611+
@Test
612+
fun `when captureFeedback is called and message is empty, lastEventId is empty`() {
613+
val (sut, mockClient) = getEnabledScopes()
614+
sut.captureFeedback(Feedback(""))
615+
assertEquals(SentryId.EMPTY_ID, sut.lastEventId)
616+
verify(mockClient, never()).captureFeedback(any(), anyOrNull(), anyOrNull())
617+
}
618+
619+
@Test
620+
fun `when captureFeedback is called on disabled client, do nothing`() {
621+
val (sut, mockClient) = getEnabledScopes()
622+
sut.close()
623+
624+
sut.captureFeedback(mock())
625+
verify(mockClient, never()).captureFeedback(any(), anyOrNull(), anyOrNull())
626+
}
627+
628+
@Test
629+
fun `when captureFeedback is called with a valid message, captureFeedback on the client should be called`() {
630+
val (sut, mockClient) = getEnabledScopes()
631+
632+
sut.captureFeedback(Feedback("test"))
633+
verify(mockClient).captureFeedback(any(), anyOrNull(), anyOrNull())
634+
}
635+
636+
@Test
637+
fun `when captureFeedback is called with a ScopeCallback then the modified scope is sent to the client`() {
638+
val (sut, mockClient) = getEnabledScopes()
639+
640+
sut.captureFeedback(Feedback("test"), null) {
641+
it.setTag("test", "testValue")
642+
}
643+
644+
verify(mockClient).captureFeedback(
645+
any(),
646+
eq(null),
647+
check {
648+
assertEquals("testValue", it.tags["test"])
649+
}
650+
)
651+
}
652+
653+
@Test
654+
fun `when captureFeedback is called with a ScopeCallback then subsequent calls to captureFeedback send the unmodified Scope to the client`() {
655+
val (sut, mockClient) = getEnabledScopes()
656+
val argumentCaptor = argumentCaptor<IScope>()
657+
658+
sut.captureFeedback(Feedback("testMessage"), null) {
659+
it.setTag("test", "testValue")
660+
}
661+
662+
sut.captureFeedback(Feedback("test"))
663+
664+
verify(mockClient, times(2)).captureFeedback(
665+
any(),
666+
anyOrNull(),
667+
argumentCaptor.capture()
668+
)
669+
670+
assertEquals("testValue", argumentCaptor.allValues[0].tags["test"])
671+
assertNull(argumentCaptor.allValues[1].tags["test"])
672+
}
673+
674+
@Test
675+
fun `when captureFeedback is called with a ScopeCallback that crashes then the feedback should still be captured`() {
676+
val (sut, mockClient, logger) = getEnabledScopes()
677+
678+
val exception = Exception("scope callback exception")
679+
sut.captureFeedback(Feedback("Hello World"), null) {
680+
throw exception
681+
}
682+
683+
verify(mockClient).captureFeedback(
684+
any(),
685+
anyOrNull(),
686+
anyOrNull()
687+
)
688+
689+
verify(logger).log(eq(SentryLevel.ERROR), any(), eq(exception))
690+
}
691+
692+
@Test
693+
fun `when captureFeedback is called with a Hint, it is passed to the client`() {
694+
val (sut, mockClient) = getEnabledScopes()
695+
val hint = Hint()
696+
697+
sut.captureFeedback(Feedback("Hello World"), hint)
698+
699+
verify(mockClient).captureFeedback(any(), eq(hint), anyOrNull())
700+
}
701+
702+
//endregion
703+
609704
//region captureException tests
610705
@Test
611706
fun `when captureException is called and exception is null, lastEventId is empty`() {

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import io.sentry.hints.Cached
1414
import io.sentry.hints.DiskFlushNotification
1515
import io.sentry.hints.TransactionEnd
1616
import io.sentry.protocol.Contexts
17+
import io.sentry.protocol.Feedback
1718
import io.sentry.protocol.Mechanism
1819
import io.sentry.protocol.Message
1920
import io.sentry.protocol.Request
@@ -289,6 +290,25 @@ class SentryClientTest {
289290
assertEquals(SentryLevel.DEBUG, sentEvent!!.level)
290291
}
291292

293+
@Test
294+
fun `when captureFeedback is called, sentry event contains feedback in contexts and header type`() {
295+
var sentEvent: SentryEvent? = null
296+
fixture.sentryOptions.setBeforeSend { e, _ -> sentEvent = e; e }
297+
val sut = fixture.getSut()
298+
sut.captureFeedback(Feedback("message"), null, null)
299+
300+
val sentFeedback = sentEvent!!.contexts.feedback
301+
assertNotNull(sentFeedback)
302+
assertEquals("message", sentFeedback.message)
303+
304+
verify(fixture.transport).send(
305+
check {
306+
assertEquals(SentryItemType.Feedback, it.items.first().header.type)
307+
},
308+
anyOrNull()
309+
)
310+
}
311+
292312
@Test
293313
fun `when event has release, value from options not applied`() {
294314
val event = SentryEvent()

0 commit comments

Comments
 (0)