Skip to content

Commit

Permalink
[Diagnostics] Send backend_error_code in http request failures if ava…
Browse files Browse the repository at this point in the history
…ilable (#1825)

### Description
This adds a new property to the `http_request_performed` diagnostics
event including information of any backend provided error codes if any.

- [x] Hold until backend support has been deployed.
  • Loading branch information
tonidero authored Sep 2, 2024
1 parent 48957cd commit 79973bf
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ internal class HTTPClient(
responseTime,
requestWasError,
responseCode,
callResult?.backendErrorCode,
origin,
verificationResult,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.revenuecat.purchases.common.networking.Endpoint
import com.revenuecat.purchases.common.networking.HTTPResult
import com.revenuecat.purchases.common.verboseLog
import com.revenuecat.purchases.strings.OfflineEntitlementsStrings
import com.revenuecat.purchases.utils.filterNotNullValues
import com.revenuecat.purchases.utils.isAndroidNOrNewer
import java.io.IOException
import kotlin.time.Duration
Expand All @@ -31,6 +32,7 @@ internal class DiagnosticsTracker(
const val ENDPOINT_NAME_KEY = "endpoint_name"
const val SUCCESSFUL_KEY = "successful"
const val RESPONSE_CODE_KEY = "response_code"
const val BACKEND_ERROR_CODE_KEY = "backend_error_code"
const val ETAG_HIT_KEY = "etag_hit"
const val VERIFICATION_RESULT_KEY = "verification_result"
const val RESPONSE_TIME_MILLIS_KEY = "response_time_millis"
Expand All @@ -45,6 +47,7 @@ internal class DiagnosticsTracker(
responseTime: Duration,
wasSuccessful: Boolean,
responseCode: Int,
backendErrorCode: Int?,
resultOrigin: HTTPResult.Origin?,
verificationResult: VerificationResult,
) {
Expand All @@ -57,9 +60,10 @@ internal class DiagnosticsTracker(
RESPONSE_TIME_MILLIS_KEY to responseTime.inWholeMilliseconds,
SUCCESSFUL_KEY to wasSuccessful,
RESPONSE_CODE_KEY to responseCode,
BACKEND_ERROR_CODE_KEY to backendErrorCode,
ETAG_HIT_KEY to eTagHit,
VERIFICATION_RESULT_KEY to verificationResult.name,
),
).filterNotNullValues(),
),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ private fun BackendErrorCode.toPurchasesError(underlyingErrorMessage: String) =
PurchasesError(this.toPurchasesErrorCode(), underlyingErrorMessage)

internal fun HTTPResult.toPurchasesError(): PurchasesError {
val errorCode = if (body.has("code")) body.get("code") as Int else null
val errorMessage = if (body.has("message")) body.get("message") as String else ""
val errorCode = backendErrorCode
val errorMessage = backendErrorMessage ?: ""

return errorCode?.let { BackendErrorCode.valueOf(it) }?.toPurchasesError(errorMessage)
?: PurchasesError(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.revenuecat.purchases.common.networking

import com.revenuecat.purchases.VerificationResult
import com.revenuecat.purchases.common.isSuccessful
import org.json.JSONObject
import java.util.Date

Expand Down Expand Up @@ -51,6 +52,15 @@ internal data class HTTPResult(

val body: JSONObject = payload.takeIf { it.isNotBlank() }?.let { JSONObject(it) } ?: JSONObject()

val backendErrorCode: Int? = if (!isSuccessful()) body.optInt("code").takeIf { it > 0 } else null
val backendErrorMessage: String? = if (!isSuccessful()) {
body.optString(
"message",
).takeIf { it.isNotBlank() }
} else {
null
}

fun serialize(): String {
val jsonObject = JSONObject().apply {
put(SERIALIZATION_NAME_RESPONSE_CODE, responseCode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ internal class HTTPClientTest: BaseHTTPClientTest() {
fun `performRequest tracks http request performed diagnostic event if request successful`() {
val dateProvider = mockk<DateProvider>()
val diagnosticsTracker = mockk<DiagnosticsTracker>()
every { diagnosticsTracker.trackHttpRequestPerformed(any(), any(), any(), any(), any(), any()) } just Runs
every { diagnosticsTracker.trackHttpRequestPerformed(any(), any(), any(), any(), any(), any(), any()) } just Runs

client = createClient(diagnosticsTracker = diagnosticsTracker, dateProvider = dateProvider)

Expand All @@ -519,15 +519,15 @@ internal class HTTPClientTest: BaseHTTPClientTest() {
server.takeRequest()

verify(exactly = 1) {
diagnosticsTracker.trackHttpRequestPerformed(endpoint, responseTime, true, responseCode, HTTPResult.Origin.BACKEND, VerificationResult.NOT_REQUESTED)
diagnosticsTracker.trackHttpRequestPerformed(endpoint, responseTime, true, responseCode, null, HTTPResult.Origin.BACKEND, VerificationResult.NOT_REQUESTED)
}
}

@Test
fun `performRequest tracks http request performed diagnostic event if request fails`() {
val dateProvider = mockk<DateProvider>()
val diagnosticsTracker = mockk<DiagnosticsTracker>()
every { diagnosticsTracker.trackHttpRequestPerformed(any(), any(), any(), any(), any(), any()) } just Runs
every { diagnosticsTracker.trackHttpRequestPerformed(any(), any(), any(), any(), any(), any(), any()) } just Runs

client = createClient(diagnosticsTracker = diagnosticsTracker, dateProvider = dateProvider)

Expand All @@ -536,10 +536,11 @@ internal class HTTPClientTest: BaseHTTPClientTest() {
val requestStartTime = 1676379370000L // Tuesday, February 14, 2023 12:56:10:000 PM GMT
val requestEndTime = 1676379370123L // Tuesday, February 14, 2023 12:56:10:123 PM GMT
val responseTime = (requestEndTime - requestStartTime).milliseconds
val backendErrorCode = 1234

enqueue(
endpoint,
expectedResult = HTTPResult.createResult(responseCode = responseCode)
expectedResult = HTTPResult.createResult(responseCode = responseCode, payload = "{\"code\":$backendErrorCode}")
)

every { dateProvider.now } returnsMany listOf(Date(requestStartTime), Date(requestEndTime))
Expand All @@ -548,15 +549,15 @@ internal class HTTPClientTest: BaseHTTPClientTest() {
server.takeRequest()

verify(exactly = 1) {
diagnosticsTracker.trackHttpRequestPerformed(endpoint, responseTime, false, responseCode, HTTPResult.Origin.BACKEND, VerificationResult.NOT_REQUESTED)
diagnosticsTracker.trackHttpRequestPerformed(endpoint, responseTime, false, responseCode, backendErrorCode, HTTPResult.Origin.BACKEND, VerificationResult.NOT_REQUESTED)
}
}

@Test
fun `performRequest tracks http request performed diagnostic event if request throws Exception`() {
val dateProvider = mockk<DateProvider>()
val diagnosticsTracker = mockk<DiagnosticsTracker>()
every { diagnosticsTracker.trackHttpRequestPerformed(any(), any(), any(), any(), any(), any()) } just Runs
every { diagnosticsTracker.trackHttpRequestPerformed(any(), any(), any(), any(), any(), any(), any()) } just Runs
every { dateProvider.now } returns Date(1676379370000) // Tuesday, February 14, 2023 12:56:10 PM GMT
client = createClient(diagnosticsTracker = diagnosticsTracker, dateProvider = dateProvider)

Expand All @@ -581,7 +582,7 @@ internal class HTTPClientTest: BaseHTTPClientTest() {
client.performRequest(baseURL, endpoint, body = null, postFieldsToSign = null, mapOf("" to ""))
} catch (e: JSONException) {
verify(exactly = 1) {
diagnosticsTracker.trackHttpRequestPerformed(endpoint, any(), false, HTTPClient.NO_STATUS_CODE, null, VerificationResult.NOT_REQUESTED)
diagnosticsTracker.trackHttpRequestPerformed(endpoint, any(), false, HTTPClient.NO_STATUS_CODE, null, null, VerificationResult.NOT_REQUESTED)
}
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ class DiagnosticsTrackerTest {
1234L.milliseconds,
true,
200,
null,
HTTPResult.Origin.CACHE,
VerificationResult.NOT_REQUESTED
)
Expand All @@ -164,6 +165,7 @@ class DiagnosticsTrackerTest {
"response_time_millis" to 1234L,
"successful" to true,
"response_code" to 200,
"backend_error_code" to 1234,
"etag_hit" to false,
"verification_result" to "NOT_REQUESTED"
)
Expand All @@ -173,6 +175,7 @@ class DiagnosticsTrackerTest {
1234L.milliseconds,
true,
200,
1234,
HTTPResult.Origin.BACKEND,
VerificationResult.NOT_REQUESTED
)
Expand Down

0 comments on commit 79973bf

Please sign in to comment.