summaryrefslogtreecommitdiffhomepage
path: root/android/app
diff options
context:
space:
mode:
authorJonatan Rhodin <jonatan.rhodin@mullvad.net>2023-11-16 01:06:15 +0100
committerJonatan Rhodin <jonatan.rhodin@mullvad.net>2023-11-16 09:34:26 +0100
commit5aac2637cbb9c3acf5504570d8a0014d609ca33b (patch)
treee0e4404d53b5939ba650e2f1b6123d67ffa2705c /android/app
parent8afe089bb7990328e7d38b8c3133289e36f83203 (diff)
downloadmullvadvpn-5aac2637cbb9c3acf5504570d8a0014d609ca33b.tar.xz
mullvadvpn-5aac2637cbb9c3acf5504570d8a0014d609ca33b.zip
Add payment unit tests for OutOfTimeViewModel
Diffstat (limited to 'android/app')
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt152
1 files changed, 150 insertions, 2 deletions
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt
index 8c1ec10f5a..dad51eab59 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt
@@ -1,8 +1,10 @@
package net.mullvad.mullvadvpn.viewmodel
+import android.app.Activity
import androidx.lifecycle.viewModelScope
import app.cash.turbine.test
import io.mockk.coEvery
+import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
@@ -10,11 +12,19 @@ import io.mockk.unmockkAll
import io.mockk.verify
import kotlin.test.assertEquals
import kotlin.test.assertIs
+import kotlin.test.assertNull
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest
+import net.mullvad.mullvadvpn.compose.dialog.payment.PaymentDialogData
import net.mullvad.mullvadvpn.compose.state.OutOfTimeUiState
+import net.mullvad.mullvadvpn.compose.state.PaymentState
import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule
+import net.mullvad.mullvadvpn.lib.common.test.assertLists
+import net.mullvad.mullvadvpn.lib.payment.model.PaymentAvailability
+import net.mullvad.mullvadvpn.lib.payment.model.PaymentProduct
+import net.mullvad.mullvadvpn.lib.payment.model.ProductId
+import net.mullvad.mullvadvpn.lib.payment.model.PurchaseResult
import net.mullvad.mullvadvpn.model.AccountExpiry
import net.mullvad.mullvadvpn.model.DeviceState
import net.mullvad.mullvadvpn.model.TunnelState
@@ -27,6 +37,8 @@ import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState
import net.mullvad.mullvadvpn.ui.serviceconnection.authTokenCache
import net.mullvad.mullvadvpn.ui.serviceconnection.connectionProxy
+import net.mullvad.mullvadvpn.usecase.PaymentUseCase
+import net.mullvad.mullvadvpn.util.toPaymentDialogData
import net.mullvad.talpid.util.EventNotifier
import org.joda.time.DateTime
import org.joda.time.ReadableInstant
@@ -42,6 +54,8 @@ class OutOfTimeViewModelTest {
MutableStateFlow<ServiceConnectionState>(ServiceConnectionState.Disconnected)
private val accountExpiryState = MutableStateFlow<AccountExpiry>(AccountExpiry.Missing)
private val deviceState = MutableStateFlow<DeviceState>(DeviceState.Initial)
+ private val paymentAvailability = MutableStateFlow<PaymentAvailability?>(null)
+ private val purchaseResult = MutableStateFlow<PurchaseResult?>(null)
// Service connections
private val mockServiceConnectionContainer: ServiceConnectionContainer = mockk()
@@ -50,15 +64,17 @@ class OutOfTimeViewModelTest {
// Event notifiers
private val eventNotifierTunnelRealState = EventNotifier<TunnelState>(TunnelState.Disconnected)
- private val mockAccountRepository: AccountRepository = mockk()
+ private val mockAccountRepository: AccountRepository = mockk(relaxed = true)
private val mockDeviceRepository: DeviceRepository = mockk()
private val mockServiceConnectionManager: ServiceConnectionManager = mockk()
+ private val mockPaymentUseCase: PaymentUseCase = mockk(relaxed = true)
private lateinit var viewModel: OutOfTimeViewModel
@Before
fun setUp() {
mockkStatic(SERVICE_CONNECTION_MANAGER_EXTENSIONS)
+ mockkStatic(PURCHASE_RESULT_EXTENSIONS_CLASS)
every { mockServiceConnectionManager.connectionState } returns serviceConnectionState
@@ -70,11 +86,16 @@ class OutOfTimeViewModelTest {
every { mockDeviceRepository.deviceState } returns deviceState
+ coEvery { mockPaymentUseCase.purchaseResult } returns purchaseResult
+
+ coEvery { mockPaymentUseCase.paymentAvailability } returns paymentAvailability
+
viewModel =
OutOfTimeViewModel(
accountRepository = mockAccountRepository,
serviceConnectionManager = mockServiceConnectionManager,
deviceRepository = mockDeviceRepository,
+ paymentUseCase = mockPaymentUseCase,
pollAccountExpiry = false
)
}
@@ -112,9 +133,9 @@ class OutOfTimeViewModelTest {
// Act, Assert
viewModel.uiState.test {
assertEquals(OutOfTimeUiState(deviceName = ""), awaitItem())
+ eventNotifierTunnelRealState.notify(tunnelRealStateTestItem)
serviceConnectionState.value =
ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
- eventNotifierTunnelRealState.notify(tunnelRealStateTestItem)
val result = awaitItem()
assertEquals(tunnelRealStateTestItem, result.tunnelState)
}
@@ -149,8 +170,135 @@ class OutOfTimeViewModelTest {
verify { mockProxy.disconnect() }
}
+ @Test
+ fun testBillingProductsUnavailableState() = runTest {
+ // Arrange
+ val productsUnavailable = PaymentAvailability.ProductsUnavailable
+ paymentAvailability.value = productsUnavailable
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.NoPayment>(result)
+ }
+ }
+
+ @Test
+ fun testBillingProductsGenericErrorState() = runTest {
+ // Arrange
+ val paymentAvailabilityError = PaymentAvailability.Error.Other(mockk())
+ paymentAvailability.value = paymentAvailabilityError
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.Error.Generic>(result)
+ }
+ }
+
+ @Test
+ fun testBillingProductsBillingErrorState() = runTest {
+ // Arrange
+ val paymentAvailabilityError = PaymentAvailability.Error.BillingUnavailable
+ paymentAvailability.value = paymentAvailabilityError
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.Error.Billing>(result)
+ }
+ }
+
+ @Test
+ fun testBillingProductsPaymentAvailableState() = runTest {
+ // Arrange
+ val mockProduct: PaymentProduct = mockk()
+ val expectedProductList = listOf(mockProduct)
+ val productsAvailable = PaymentAvailability.ProductsAvailable(listOf(mockProduct))
+ paymentAvailability.value = productsAvailable
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+
+ // Act, Assert
+ viewModel.uiState.test {
+ val result = awaitItem().billingPaymentState
+ assertIs<PaymentState.PaymentAvailable>(result)
+ assertLists(expectedProductList, result.products)
+ }
+ }
+
+ @Test
+ fun testBillingUserCancelled() = runTest {
+ // Arrange
+ val result = PurchaseResult.Completed.Cancelled
+ purchaseResult.value = result
+ every { result.toPaymentDialogData() } returns null
+
+ // Act, Assert
+ viewModel.uiState.test { assertNull(awaitItem().paymentDialogData) }
+ }
+
+ @Test
+ fun testBillingPurchaseSuccess() = runTest {
+ // Arrange
+ val result = PurchaseResult.Completed.Success
+ val expectedData: PaymentDialogData = mockk()
+ purchaseResult.value = result
+ serviceConnectionState.value =
+ ServiceConnectionState.ConnectedReady(mockServiceConnectionContainer)
+ every { result.toPaymentDialogData() } returns expectedData
+
+ // Act, Assert
+ viewModel.uiState.test { assertEquals(expectedData, awaitItem().paymentDialogData) }
+ }
+
+ @Test
+ fun testStartBillingPayment() {
+ // Arrange
+ val mockProductId = ProductId("MOCK")
+ val mockActivityProvider = mockk<() -> Activity>()
+
+ // Act
+ viewModel.startBillingPayment(mockProductId, mockActivityProvider)
+
+ // Assert
+ coVerify { mockPaymentUseCase.purchaseProduct(mockProductId, mockActivityProvider) }
+ }
+
+ @Test
+ fun testOnClosePurchaseResultDialogSuccessful() {
+ // Arrange
+
+ // Act
+ viewModel.onClosePurchaseResultDialog(success = true)
+
+ // Assert
+ verify { mockAccountRepository.fetchAccountExpiry() }
+ coVerify { mockPaymentUseCase.resetPurchaseResult() }
+ }
+
+ @Test
+ fun testOnClosePurchaseResultDialogNotSuccessful() {
+ // Arrange
+
+ // Act
+ viewModel.onClosePurchaseResultDialog(success = false)
+
+ // Assert
+ coVerify { mockPaymentUseCase.queryPaymentAvailability() }
+ coVerify { mockPaymentUseCase.resetPurchaseResult() }
+ }
+
companion object {
private const val SERVICE_CONNECTION_MANAGER_EXTENSIONS =
"net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManagerExtensionsKt"
+ private const val PURCHASE_RESULT_EXTENSIONS_CLASS =
+ "net.mullvad.mullvadvpn.util.PurchaseResultExtensionsKt"
}
}