Skip to content

Commit 937879e

Browse files
authored
Fix Ui tests receiving empty requests (#3094)
* cleaned up MockRelay, removing requests that are not envelopes (we don't have such) * added a check to discard already received envelopes, sent twice for any reason)
1 parent be4794a commit 937879e

File tree

4 files changed

+66
-56
lines changed

4 files changed

+66
-56
lines changed

sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ class EnvelopeTests : BaseUiTest() {
4242
assertTrue(event.message?.formatted == "Message captured during test")
4343
}
4444
assertNoOtherEnvelopes()
45-
assertNoOtherRequests()
4645
}
4746
}
4847

@@ -170,7 +169,6 @@ class EnvelopeTests : BaseUiTest() {
170169
assertNotNull(transactionData)
171170
}
172171
assertNoOtherEnvelopes()
173-
assertNoOtherRequests()
174172
}
175173
}
176174

@@ -205,7 +203,6 @@ class EnvelopeTests : BaseUiTest() {
205203
assertEquals(ProfilingTraceData.TRUNCATION_REASON_TIMEOUT, profilingTraceData.truncationReason)
206204
}
207205
assertNoOtherEnvelopes()
208-
assertNoOtherRequests()
209206
}
210207
}
211208

sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/SdkInitTests.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ class SdkInitTests : BaseUiTest() {
7272
assertEquals("e2etests2", profilingTraceData.transactionName)
7373
}
7474
assertNoOtherEnvelopes()
75-
assertNoOtherRequests()
7675
}
7776
}
7877
}

sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/mockservers/MockRelay.kt

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import okhttp3.mockwebserver.Dispatcher
66
import okhttp3.mockwebserver.MockResponse
77
import okhttp3.mockwebserver.MockWebServer
88
import okhttp3.mockwebserver.RecordedRequest
9+
import kotlin.test.assertNotNull
910

1011
/** Mocks a relay server. */
1112
class MockRelay(
@@ -22,31 +23,40 @@ class MockRelay(
2223
/** List of unasserted requests sent to the [envelopePath]. */
2324
private val unassertedEnvelopes = mutableListOf<RelayAsserter.RelayResponse>()
2425

25-
/** List of unasserted requests not contained in [unassertedEnvelopes]. */
26-
private val unassertedRequests = mutableListOf<RelayAsserter.RelayResponse>()
27-
2826
/** List of responses to return when a request is sent. */
2927
private val responses = mutableListOf<(RecordedRequest) -> MockResponse?>()
3028

29+
/** Set to check already received envelopes, to avoid duplicates due to e.g. retrying. */
30+
private val receivedEnvelopes: MutableSet<String> = HashSet()
31+
3132
init {
3233
relay.dispatcher = object : Dispatcher() {
3334
override fun dispatch(request: RecordedRequest): MockResponse {
35+
// If a request with a body size of 0 is received, we drop it.
36+
// This shouldn't happen in reality, but it rarely happens in tests.
37+
if (request.bodySize == 0L || request.failure != null) {
38+
return MockResponse()
39+
}
3440
// We check if there is any custom response previously set to return to this request,
3541
// otherwise we return a successful MockResponse.
3642
val response = responses.asSequence()
3743
.mapNotNull { it(request) }
3844
.firstOrNull()
3945
?: MockResponse()
4046

41-
// Based on the path of the request, we populate the right list.
42-
val relayResponse = RelayAsserter.RelayResponse(request, response)
43-
when (request.path) {
44-
envelopePath -> {
45-
unassertedEnvelopes.add(relayResponse)
46-
}
47-
else -> {
48-
unassertedRequests.add(relayResponse)
47+
// We should receive only envelopes on this path.
48+
if (request.path == envelopePath) {
49+
val relayResponse = RelayAsserter.RelayResponse(request, response)
50+
assertNotNull(relayResponse.envelope)
51+
val envelopeId: String = relayResponse.envelope!!.header.eventId!!.toString()
52+
// If we already received the envelope (e.g. retrying mechanism) we drop it
53+
if (receivedEnvelopes.contains(envelopeId)) {
54+
return MockResponse()
4955
}
56+
receivedEnvelopes.add(envelopeId)
57+
unassertedEnvelopes.add(relayResponse)
58+
} else {
59+
throw AssertionError("Expected $envelopePath, but the request path was ${request.path}")
5060
}
5161

5262
// If we are waiting for requests to be received, we decrement the associated counter.
@@ -62,7 +72,10 @@ class MockRelay(
6272
fun createMockDsn() = "http://key@${relay.hostName}:${relay.port}/$dsnProject"
6373

6474
/** Starts the mock relay server. */
65-
fun start() = relay.start()
75+
fun start() {
76+
receivedEnvelopes.clear()
77+
relay.start()
78+
}
6679

6780
/** Shutdown the mock relay server and clear everything. */
6881
fun shutdown() {
@@ -98,6 +111,6 @@ class MockRelay(
98111
if (waitForRequests) {
99112
waitUntilIdle()
100113
}
101-
assertion(RelayAsserter(unassertedEnvelopes, unassertedRequests))
114+
assertion(RelayAsserter(unassertedEnvelopes))
102115
}
103116
}

sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/mockservers/RelayAsserter.kt

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
package io.sentry.uitest.android.mockservers
22

33
import io.sentry.EnvelopeReader
4+
import io.sentry.JsonSerializer
5+
import io.sentry.ProfilingTraceData
46
import io.sentry.Sentry
57
import io.sentry.SentryEnvelope
8+
import io.sentry.SentryEvent
9+
import io.sentry.SentryItemType
10+
import io.sentry.SentryOptions
11+
import io.sentry.protocol.SentryTransaction
612
import okhttp3.mockwebserver.MockResponse
713
import okhttp3.mockwebserver.RecordedRequest
814
import okio.GzipSource
@@ -12,40 +18,18 @@ import java.util.zip.GZIPInputStream
1218

1319
/** Class used to assert requests sent to [MockRelay]. */
1420
class RelayAsserter(
15-
private val unassertedEnvelopes: MutableList<RelayResponse>,
16-
private val unassertedRequests: MutableList<RelayResponse>
21+
private val unassertedEnvelopes: MutableList<RelayResponse>
1722
) {
18-
19-
/**
20-
* Asserts an envelope request exists and allows to make other assertions on the first one and on its response.
21-
* The asserted envelope request is then removed from internal list of unasserted envelopes.
22-
*/
23-
fun assertFirstRawEnvelope(assertion: ((relayResponse: RelayResponse) -> Unit)? = null) {
24-
val relayResponse = unassertedEnvelopes.removeFirstOrNull()
25-
?: throw AssertionError("No envelope request found")
26-
assertion?.let { it(relayResponse) }
27-
}
28-
29-
/**
30-
* Asserts a request exists and makes other assertions on the first one and on its response.
31-
* The asserted request is then removed from internal list of unasserted requests.
32-
*/
33-
fun assertRawRequest(assertion: ((request: RecordedRequest, response: MockResponse) -> Unit)? = null) {
34-
val relayResponse = unassertedRequests.removeFirstOrNull()
35-
?: throw AssertionError("No raw request found")
36-
assertion?.let {
37-
it(relayResponse.request, relayResponse.response)
38-
}
39-
}
23+
private val originalUnassertedEnvelopes: MutableList<RelayResponse> = ArrayList(unassertedEnvelopes)
4024

4125
/**
4226
* Parses the first request as an envelope and makes other assertions through a [EnvelopeAsserter].
4327
* The asserted envelope is then removed from internal list of unasserted envelopes.
4428
*/
4529
fun assertFirstEnvelope(assertion: (asserter: EnvelopeAsserter) -> Unit) {
46-
assertFirstRawEnvelope { relayResponse ->
47-
relayResponse.assert(assertion)
48-
}
30+
val relayResponse = unassertedEnvelopes.removeFirstOrNull()
31+
?: throw AssertionError("No envelope request found")
32+
relayResponse.assert(assertion)
4933
}
5034

5135
/**
@@ -63,22 +47,39 @@ class RelayAsserter(
6347
/** Asserts no other envelopes were sent. */
6448
fun assertNoOtherEnvelopes() {
6549
if (unassertedEnvelopes.isNotEmpty()) {
66-
throw AssertionError("There were other ${unassertedEnvelopes.size} envelope requests: $unassertedEnvelopes")
50+
throw AssertionError(
51+
"There was a total of ${originalUnassertedEnvelopes.size} envelopes: " +
52+
originalUnassertedEnvelopes.joinToString { describeEnvelope(it.envelope!!) }
53+
)
6754
}
6855
}
6956

70-
/** Asserts no other raw requests were sent. */
71-
fun assertNoOtherRawRequests() {
72-
assertNoOtherEnvelopes()
73-
if (unassertedRequests.isNotEmpty()) {
74-
throw AssertionError("There were other ${unassertedRequests.size} requests: $unassertedRequests")
57+
/** Function used to describe the content of the envelope to print in the logs. For debugging purposes only. */
58+
private fun describeEnvelope(envelope: SentryEnvelope): String {
59+
var descr = ""
60+
envelope.items.forEach { item ->
61+
when (item.header.type) {
62+
SentryItemType.Event -> {
63+
val deserialized = JsonSerializer(SentryOptions())
64+
.deserialize(item.data.inputStream().reader(), SentryEvent::class.java)!!
65+
descr += "Event (${deserialized.eventId}) - message: ${deserialized.message!!.formatted} -- "
66+
}
67+
SentryItemType.Transaction -> {
68+
val deserialized = JsonSerializer(SentryOptions())
69+
.deserialize(item.data.inputStream().reader(), SentryTransaction::class.java)!!
70+
descr += "Transaction (${deserialized.eventId}) - transaction: ${deserialized.transaction} - spans: ${deserialized.spans.joinToString { "${it.op} ${it.description}" }} -- "
71+
}
72+
SentryItemType.Profile -> {
73+
val deserialized = JsonSerializer(SentryOptions())
74+
.deserialize(item.data.inputStream().reader(), ProfilingTraceData::class.java)!!
75+
descr += "Profile (${deserialized.profileId}) - transactionName: ${deserialized.transactionName} -- "
76+
}
77+
else -> {
78+
descr += "${item.header.type} -- "
79+
}
80+
}
7581
}
76-
}
77-
78-
/** Asserts no other requests or envelopes were sent. */
79-
fun assertNoOtherRequests() {
80-
assertNoOtherEnvelopes()
81-
assertNoOtherRawRequests()
82+
return "*** Envelope: $descr ***"
8283
}
8384

8485
data class RelayResponse(val request: RecordedRequest, val response: MockResponse) {

0 commit comments

Comments
 (0)