Skip to content

Commit

Permalink
Merge branch 'check-for-empty-string-when-setting-droid-1612'
Browse files Browse the repository at this point in the history
  • Loading branch information
Pururun committed Dec 3, 2024
2 parents ce8c122 + 41e9fea commit 862b958
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 2 deletions.
3 changes: 3 additions & 0 deletions android/lib/billing/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ dependencies {
// Management service
implementation(projects.lib.daemonGrpc)

// Logger
implementation(libs.kermit)

// Test dependencies
testRuntimeOnly(Dependencies.junitJupiterEngine)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ package net.mullvad.mullvadvpn.lib.billing

import android.app.Activity
import arrow.core.Either
import arrow.core.flatMap
import arrow.core.left
import arrow.core.raise.either
import arrow.core.raise.ensure
import arrow.core.right
import co.touchlab.kermit.Logger
import com.android.billingclient.api.BillingClient.BillingResponseCode
import com.android.billingclient.api.Purchase
import kotlinx.coroutines.flow.Flow
Expand All @@ -19,6 +23,7 @@ import net.mullvad.mullvadvpn.lib.billing.extension.toPurchaseResult
import net.mullvad.mullvadvpn.lib.billing.model.BillingException
import net.mullvad.mullvadvpn.lib.billing.model.PurchaseEvent
import net.mullvad.mullvadvpn.lib.model.PlayPurchase
import net.mullvad.mullvadvpn.lib.model.PlayPurchaseInitError
import net.mullvad.mullvadvpn.lib.model.PlayPurchasePaymentToken
import net.mullvad.mullvadvpn.lib.payment.PaymentRepository
import net.mullvad.mullvadvpn.lib.payment.ProductIds
Expand Down Expand Up @@ -78,7 +83,7 @@ class BillingPaymentRepository(
// Get transaction id
emit(PurchaseResult.FetchingObfuscationId)
val obfuscatedId: PlayPurchasePaymentToken =
initialisePurchase()
initializePurchase()
.fold(
{
emit(PurchaseResult.Error.TransactionIdError(productId, null))
Expand Down Expand Up @@ -148,7 +153,15 @@ class BillingPaymentRepository(
.bind()
}

private suspend fun initialisePurchase() = playPurchaseRepository.initializePlayPurchase()
private suspend fun initializePurchase() =
playPurchaseRepository.initializePlayPurchase().flatMap {
if (it.value.isNotEmpty()) {
it.right()
} else {
Logger.e("PlayPurchasePaymentToken is empty")
PlayPurchaseInitError.OtherError.left()
}
}

private suspend fun verifyPurchase(purchase: Purchase) =
playPurchaseRepository.verifyPlayPurchase(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package net.mullvad.mullvadvpn.lib.billing

import android.app.Activity
import android.content.Context
import co.touchlab.kermit.Logger
import com.android.billingclient.api.BillingClient
import com.android.billingclient.api.BillingClient.BillingResponseCode
import com.android.billingclient.api.BillingClientStateListener
Expand Down Expand Up @@ -124,6 +125,11 @@ class BillingRepository(context: Context) {
return try {
ensureConnected()

if (obfuscatedId.isEmpty()) {
Logger.e("Obfuscated id is empty")
return BillingResult.newBuilder().setResponseCode(BillingResponseCode.ERROR).build()
}

val productDetailsParamsList =
listOf(
BillingFlowParams.ProductDetailsParams.newBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,32 @@ class BillingPaymentRepositoryTest {
}
}

@Test
fun `purchaseProduct should return TransactionIdError when PlayPurchasePaymentToken is empty`() =
runTest {
// Arrange
val mockProductId = ProductId("MOCK")
val mockProductDetailsResult = mockk<ProductDetailsResult>()
val mockProductDetails: ProductDetails = mockk()
every { mockProductDetails.productId } returns mockProductId.value
every { mockProductDetailsResult.billingResult.responseCode } returns
BillingResponseCode.OK
every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails)
coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns
mockProductDetailsResult
coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns
PlayPurchasePaymentToken("").right()

// Act, Assert
paymentRepository.purchaseProduct(mockProductId, mockk()).test {
assertIs<PurchaseResult.FetchingProducts>(awaitItem())
assertIs<PurchaseResult.FetchingObfuscationId>(awaitItem())
val result = awaitItem()
assertIs<PurchaseResult.Error.TransactionIdError>(result)
awaitComplete()
}
}

@Test
fun `purchaseProduct should return BillingError on billing unavailable from startPurchaseFlow`() =
runTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,27 @@ class BillingRepositoryTest {
assertEquals(mockBillingResult, result)
}

@Test
fun `starting purchase flow with empty transaction id should return error`() = runTest {
// Arrange
val transactionId = ""
val mockProductDetails: ProductDetails = mockk(relaxed = true)
val mockActivityProvider: () -> Activity = mockk()
every { mockBillingClient.isReady } returns true
every { mockBillingClient.connectionState } returns BillingClient.ConnectionState.CONNECTED

// Act
val result =
billingRepository.startPurchaseFlow(
mockProductDetails,
transactionId,
mockActivityProvider,
)

// Assert
assertEquals(BillingResponseCode.ERROR, result.responseCode)
}

@Test
fun `when billing client query purchases returns OK query purchases should return OK`() =
runTest {
Expand Down

0 comments on commit 862b958

Please sign in to comment.