Implement initial support for IAP data.

This commit is contained in:
Alex Hart
2024-12-19 16:34:29 -04:00
committed by Greyson Parrelli
parent f537fa6436
commit f2b4bd0585
35 changed files with 957 additions and 241 deletions

View File

@@ -0,0 +1,162 @@
package org.thoughtcrime.securesms.migrations
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.mockk.Called
import io.mockk.coEvery
import io.mockk.verify
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.signal.core.util.billing.BillingPurchaseResult
import org.signal.core.util.billing.BillingPurchaseState
import org.signal.core.util.deleteAll
import org.thoughtcrime.securesms.database.InAppPaymentSubscriberTable
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.model.InAppPaymentSubscriberRecord
import org.thoughtcrime.securesms.database.model.databaseprotos.InAppPaymentData
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.testing.SignalActivityRule
import org.thoughtcrime.securesms.testing.assertIs
import org.whispersystems.signalservice.api.storage.IAPSubscriptionId
import org.whispersystems.signalservice.api.subscriptions.SubscriberId
@RunWith(AndroidJUnit4::class)
class GooglePlayBillingPurchaseTokenMigrationJobTest {
@get:Rule
val harness = SignalActivityRule()
@Before
fun setUp() {
SignalDatabase.inAppPaymentSubscribers.writableDatabase.deleteAll(InAppPaymentSubscriberTable.TABLE_NAME)
}
@Test
fun givenNoSubscribers_whenIRunJob_thenIExpectNoBillingAccess() {
val job = GooglePlayBillingPurchaseTokenMigrationJob()
job.run()
verify { AppDependencies.billingApi wasNot Called }
}
@Test
fun givenSubscriberWithAppleData_whenIRunJob_thenIExpectNoBillingAccess() {
SignalDatabase.inAppPaymentSubscribers.insertOrReplace(
InAppPaymentSubscriberRecord(
subscriberId = SubscriberId.generate(),
currency = null,
type = InAppPaymentSubscriberRecord.Type.BACKUP,
requiresCancel = false,
paymentMethodType = InAppPaymentData.PaymentMethodType.GOOGLE_PLAY_BILLING,
iapSubscriptionId = IAPSubscriptionId.AppleIAPOriginalTransactionId(1000L)
)
)
val job = GooglePlayBillingPurchaseTokenMigrationJob()
job.run()
verify { AppDependencies.billingApi wasNot Called }
}
@Test
fun givenSubscriberWithGoogleToken_whenIRunJob_thenIExpectNoBillingAccess() {
SignalDatabase.inAppPaymentSubscribers.insertOrReplace(
InAppPaymentSubscriberRecord(
subscriberId = SubscriberId.generate(),
currency = null,
type = InAppPaymentSubscriberRecord.Type.BACKUP,
requiresCancel = false,
paymentMethodType = InAppPaymentData.PaymentMethodType.GOOGLE_PLAY_BILLING,
iapSubscriptionId = IAPSubscriptionId.GooglePlayBillingPurchaseToken("testToken")
)
)
val job = GooglePlayBillingPurchaseTokenMigrationJob()
job.run()
verify { AppDependencies.billingApi wasNot Called }
}
@Test
fun givenSubscriberWithPlaceholderAndNoBillingAccess_whenIRunJob_thenIExpectNoUpdate() {
SignalDatabase.inAppPaymentSubscribers.insertOrReplace(
InAppPaymentSubscriberRecord(
subscriberId = SubscriberId.generate(),
currency = null,
type = InAppPaymentSubscriberRecord.Type.BACKUP,
requiresCancel = false,
paymentMethodType = InAppPaymentData.PaymentMethodType.GOOGLE_PLAY_BILLING,
iapSubscriptionId = IAPSubscriptionId.GooglePlayBillingPurchaseToken("-")
)
)
coEvery { AppDependencies.billingApi.isApiAvailable() } returns false
val job = GooglePlayBillingPurchaseTokenMigrationJob()
job.run()
val sub = SignalDatabase.inAppPaymentSubscribers.getBackupsSubscriber()
sub?.iapSubscriptionId?.purchaseToken assertIs "-"
}
@Test
fun givenSubscriberWithPlaceholderAndNoPurchase_whenIRunJob_thenIExpectNoUpdate() {
SignalDatabase.inAppPaymentSubscribers.insertOrReplace(
InAppPaymentSubscriberRecord(
subscriberId = SubscriberId.generate(),
currency = null,
type = InAppPaymentSubscriberRecord.Type.BACKUP,
requiresCancel = false,
paymentMethodType = InAppPaymentData.PaymentMethodType.GOOGLE_PLAY_BILLING,
iapSubscriptionId = IAPSubscriptionId.GooglePlayBillingPurchaseToken("-")
)
)
coEvery { AppDependencies.billingApi.isApiAvailable() } returns true
coEvery { AppDependencies.billingApi.queryPurchases() } returns BillingPurchaseResult.None
val job = GooglePlayBillingPurchaseTokenMigrationJob()
job.run()
val sub = SignalDatabase.inAppPaymentSubscribers.getBackupsSubscriber()
sub?.iapSubscriptionId?.purchaseToken assertIs "-"
}
@Test
fun givenSubscriberWithPurchase_whenIRunJob_thenIExpectUpdate() {
SignalDatabase.inAppPaymentSubscribers.insertOrReplace(
InAppPaymentSubscriberRecord(
subscriberId = SubscriberId.generate(),
currency = null,
type = InAppPaymentSubscriberRecord.Type.BACKUP,
requiresCancel = false,
paymentMethodType = InAppPaymentData.PaymentMethodType.GOOGLE_PLAY_BILLING,
iapSubscriptionId = IAPSubscriptionId.GooglePlayBillingPurchaseToken("-")
)
)
coEvery { AppDependencies.billingApi.isApiAvailable() } returns true
coEvery { AppDependencies.billingApi.queryPurchases() } returns BillingPurchaseResult.Success(
purchaseState = BillingPurchaseState.PURCHASED,
purchaseToken = "purchaseToken",
isAcknowledged = true,
purchaseTime = System.currentTimeMillis(),
isAutoRenewing = true
)
val job = GooglePlayBillingPurchaseTokenMigrationJob()
job.run()
val sub = SignalDatabase.inAppPaymentSubscribers.getBackupsSubscriber()
sub?.iapSubscriptionId?.purchaseToken assertIs "purchaseToken"
}
}

View File

@@ -36,14 +36,14 @@ class SubscriberIdMigrationJobTest {
@Test
fun givenUSDSubscriber_whenIRunSubscriberIdMigrationJob_thenIExpectASingleEntry() {
val subscriberId = SubscriberId.generate()
SignalStore.inAppPayments.setSubscriberCurrency(Currency.getInstance("USD"), InAppPaymentSubscriberRecord.Type.DONATION)
SignalStore.inAppPayments.setRecurringDonationCurrency(Currency.getInstance("USD"))
SignalStore.inAppPayments.setSubscriber("USD", subscriberId)
SignalStore.inAppPayments.setSubscriptionPaymentSourceType(PaymentSourceType.PayPal)
SignalStore.inAppPayments.shouldCancelSubscriptionBeforeNextSubscribeAttempt = true
testSubject.run()
val actual = SignalDatabase.inAppPaymentSubscribers.getByCurrencyCode("USD", InAppPaymentSubscriberRecord.Type.DONATION)
val actual = SignalDatabase.inAppPaymentSubscribers.getByCurrencyCode("USD")
actual.assertIsNotNull()
actual!!.subscriberId.bytes assertIs subscriberId.bytes