Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix onError of unsuccessful /identify calls #359

Merged
merged 5 commits into from Sep 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 2 additions & 10 deletions common/src/main/java/com/revenuecat/purchases/common/Backend.kt
Expand Up @@ -320,11 +320,7 @@ class Backend(
onSuccessHandler()
}
} else {
synchronized(this@Backend) {
createAliasCallbacks.remove(cacheKey)
}?.forEach { (_, onErrorHandler) ->
onErrorHandler(result.toPurchasesError().also { errorLog(it) })
}
onError(result.toPurchasesError().also { errorLog(it) })
}
}
}
Expand Down Expand Up @@ -378,11 +374,7 @@ class Backend(
}
}
} else {
synchronized(this@Backend) {
identifyCallbacks.remove(cacheKey)
}?.forEach { (_, onErrorHandler) ->
onError(result.toPurchasesError().also { errorLog(it) })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the bug 😮‍💨

I should have called onErrorHandler instead of onError

}
onError(result.toPurchasesError().also { errorLog(it) })
}
}
}
Expand Down
184 changes: 180 additions & 4 deletions common/src/test/java/com/revenuecat/purchases/common/BackendTest.kt
Expand Up @@ -10,16 +10,13 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.revenuecat.purchases.PurchaserInfo
import com.revenuecat.purchases.PurchasesError
import com.revenuecat.purchases.PurchasesErrorCode
import com.revenuecat.purchases.common.attribution.AttributionNetwork
import com.revenuecat.purchases.common.networking.HTTPResult
import com.revenuecat.purchases.models.ProductDetails
import com.revenuecat.purchases.utils.Responses
import com.revenuecat.purchases.utils.getNullableString
import io.mockk.Called
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.slot
import io.mockk.verify
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Fail.fail
Expand Down Expand Up @@ -451,6 +448,87 @@ class BackendTest {
}
}

@Test
fun `given multiple alias calls for same ids, only one is triggered, and all onError callbacks are triggered if 500`() {
val body = mapOf(
"new_app_user_id" to "newId"
)
mockResponse(
"/subscribers/$appUserID/alias",
body,
responseCode = 500,
clientException = null,
resultBody = null,
delayed = true
)
val newAppUserID = "newId"
val lock = CountDownLatch(2)
asyncBackend.createAlias(appUserID, newAppUserID, onSuccessHandler = {
fail("Shouldn't be success")
}, onErrorHandler = {
lock.countDown()
})
asyncBackend.createAlias(appUserID, newAppUserID, onSuccessHandler = {
fail("Shouldn't be success")
}, onErrorHandler = {
lock.countDown()
})
lock.await(2000, TimeUnit.MILLISECONDS)
assertThat(lock.count).isEqualTo(0)
verify(exactly = 1) {
mockClient.performRequest(
"/subscribers/${Uri.encode(appUserID)}/alias",
body,
any()
)
}
}

@Test
fun `given multiple alias calls for same ids, only one is triggered, and all onError callbacks are triggered if there's an exception`() {
val body = mapOf(
"new_app_user_id" to "newId"
)

val headers = HashMap<String, String>()
headers["Authorization"] = "Bearer $API_KEY"

val lockException = CountDownLatch(1)
every {
mockClient.performRequest(
"/subscribers/$appUserID/alias",
body,
headers
)
} answers {
lockException.await()
throw IOException()
}

val newAppUserID = "newId"
val lock = CountDownLatch(2)
asyncBackend.createAlias(appUserID, newAppUserID, onSuccessHandler = {
fail("Shouldn't be success")
}, onErrorHandler = {
lock.countDown()
})
asyncBackend.createAlias(appUserID, newAppUserID, onSuccessHandler = {
fail("Shouldn't be success")
}, onErrorHandler = {
lock.countDown()
})
lockException.countDown()
lock.await(2000, TimeUnit.MILLISECONDS)
assertThat(lock.count).isEqualTo(0)
verify(exactly = 1) {
mockClient.performRequest(
"/subscribers/${Uri.encode(appUserID)}/alias",
body,
any()
)
}
}

@Test
fun `given multiple get calls for same subscriber, only one is triggered`() {
mockResponse(
Expand Down Expand Up @@ -1082,7 +1160,7 @@ class BackendTest {
appUserID,
newAppUserID,
{ _, _ ->
fail("Should have called success")
fail("Should have called error")
},
onReceiveLoginErrorHandler
)
Expand Down Expand Up @@ -1193,6 +1271,104 @@ class BackendTest {
}
}

@Test
fun `given multiple login calls for same ids, only one http call is triggered, and all onError callbacks are called if purchaserInfo can't be parsed`() {
val newAppUserID = "newId"
val requestBody = mapOf(
"new_app_user_id" to newAppUserID,
"app_user_id" to appUserID
)
val resultBody = "{}"
mockResponse(
"/subscribers/identify",
requestBody,
responseCode = 200,
clientException = null,
resultBody = resultBody,
delayed = true
)

val lock = CountDownLatch(2)
asyncBackend.logIn(
appUserID,
newAppUserID,
{ _, _ ->
fail("Should have called error")
},
{
lock.countDown()
}
)
asyncBackend.logIn(
appUserID,
newAppUserID,
{ _, _ ->
fail("Should have called error")
},
{
lock.countDown()
}
)
lock.await(2000, TimeUnit.MILLISECONDS)
assertThat(lock.count).isEqualTo(0)
verify(exactly = 1) {
mockClient.performRequest(
"/subscribers/identify",
requestBody,
any()
)
}
}

@Test
fun `given multiple login calls for same ids, only one http call is triggered, and all onError callbacks are called if call is not successful`() {
val newAppUserID = "newId"
val requestBody = mapOf(
"new_app_user_id" to newAppUserID,
"app_user_id" to appUserID
)
val resultBody = "{}"
mockResponse(
"/subscribers/identify",
requestBody,
responseCode = 500,
clientException = null,
resultBody = resultBody,
delayed = true
)

val lock = CountDownLatch(2)
asyncBackend.logIn(
appUserID,
newAppUserID,
{ _, _ ->
fail("Should have called error")
},
{
lock.countDown()
}
)
asyncBackend.logIn(
appUserID,
newAppUserID,
{ _, _ ->
fail("Should have called error")
},
{
lock.countDown()
}
)
lock.await(2000, TimeUnit.MILLISECONDS)
assertThat(lock.count).isEqualTo(0)
verify(exactly = 1) {
mockClient.performRequest(
"/subscribers/identify",
requestBody,
any()
)
}
}

@Test
fun `given multiple post calls for same subscriber different store user ID, both are triggered`() {

Expand Down