Updated on 2026-08-14
This commit is contained in:
parent
ebb562b2a0
commit
ae759af1c7
14 changed files with 422 additions and 140 deletions
|
|
@ -16,6 +16,7 @@ import com.tangem.datasource.local.preferences.AppPreferencesStore
|
|||
import com.tangem.datasource.local.token.P2PEthPoolVaultsStore
|
||||
import com.tangem.datasource.local.token.StakingActionsStore
|
||||
import com.tangem.datasource.local.token.StakingYieldsStore
|
||||
import com.tangem.domain.staking.StakingIdFactory
|
||||
import com.tangem.domain.staking.repositories.*
|
||||
import com.tangem.domain.staking.toggles.StakingFeatureToggles
|
||||
import com.tangem.domain.staking.utils.StakingCleaner
|
||||
|
|
@ -136,10 +137,12 @@ internal object StakingDataModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideStakingCleaner(
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
stakingBalancesStore: StakingBalancesStore,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): StakingCleaner {
|
||||
return DefaultStakingCleaner(
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
stakingBalancesStore = stakingBalancesStore,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,17 @@
|
|||
package com.tangem.data.staking.utils
|
||||
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.data.staking.store.StakingBalancesStore
|
||||
import com.tangem.domain.models.staking.StakingID
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.StakingIdFactory
|
||||
import com.tangem.domain.staking.utils.StakingCleaner
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.runSuspendCatching
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Default implementation of [StakingCleaner].
|
||||
|
|
@ -15,15 +22,46 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultStakingCleaner(
|
||||
private val stakingIdFactory: StakingIdFactory,
|
||||
private val stakingBalancesStore: StakingBalancesStore,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : StakingCleaner {
|
||||
|
||||
override suspend fun invoke(userWalletId: UserWalletId, stakingIds: Set<StakingID>) {
|
||||
if (stakingIds.isEmpty()) return
|
||||
override suspend fun invoke(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
|
||||
if (currencies.isEmpty()) {
|
||||
Timber.d("No currencies to clear for wallet: $userWalletId")
|
||||
return
|
||||
}
|
||||
|
||||
with(dispatchers.default) {
|
||||
stakingBalancesStore.clear(userWalletId, stakingIds)
|
||||
val stakingIds = currencies.mapNotNullTo(hashSetOf()) {
|
||||
stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = it).getOrNull()
|
||||
}
|
||||
|
||||
if (stakingIds.isEmpty()) {
|
||||
Timber.d("All currencies have no stakingIds to clear for wallet: $userWalletId")
|
||||
return
|
||||
}
|
||||
|
||||
invoke(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
}
|
||||
|
||||
override suspend fun invoke(userWalletId: UserWalletId, stakingIds: Set<StakingID>) {
|
||||
if (stakingIds.isEmpty()) {
|
||||
Timber.d("No stakingIds to clear for wallet: $userWalletId")
|
||||
return
|
||||
}
|
||||
|
||||
withContext(dispatchers.default) {
|
||||
awaitAll(
|
||||
async { clearStatusesStore(userWalletId = userWalletId, stakingIds = stakingIds) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun clearStatusesStore(userWalletId: UserWalletId, stakingIds: Set<StakingID>) {
|
||||
runSuspendCatching {
|
||||
stakingBalancesStore.clear(userWalletId, stakingIds)
|
||||
}
|
||||
.onFailure { Timber.e(it, "Failed to clear yield balance statuses for wallet: $userWalletId") }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +1,146 @@
|
|||
package com.tangem.data.staking.utils
|
||||
|
||||
import arrow.core.right
|
||||
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
||||
import com.tangem.data.staking.store.StakingBalancesStore
|
||||
import com.tangem.domain.models.staking.StakingID
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.StakingIdFactory
|
||||
import com.tangem.domain.staking.model.StakingIntegrationID
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerifyOrder
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class DefaultStakingCleanerTest {
|
||||
|
||||
private val stakingIdFactory = mockk<StakingIdFactory>(relaxed = true)
|
||||
private val stakingBalancesStore = mockk<StakingBalancesStore>(relaxed = true)
|
||||
private val cleaner = DefaultStakingCleaner(
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
stakingBalancesStore = stakingBalancesStore,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
)
|
||||
|
||||
private val userWalletId = UserWalletId("011")
|
||||
private val stakingIds = setOf(
|
||||
StakingID(integrationId = StakingIntegrationID.StakeKit.Coin.Cardano.value, address = "0x1"),
|
||||
)
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
clearMocks(stakingBalancesStore)
|
||||
clearMocks(stakingIdFactory, stakingBalancesStore)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should clear yields balances when called`() = runTest {
|
||||
// Act
|
||||
cleaner(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class ClearByStakingIds {
|
||||
|
||||
// Assert
|
||||
coVerifyOrder {
|
||||
stakingBalancesStore.clear(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
private val stakingIds = setOf(
|
||||
StakingID(integrationId = StakingIntegrationID.StakeKit.Coin.Cardano.value, address = "0x1"),
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `should clear yields balances when called`() = runTest {
|
||||
// Act
|
||||
cleaner(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
|
||||
// Assert
|
||||
coVerifyOrder {
|
||||
stakingBalancesStore.clear(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should handle empty stakingIds`() = runTest {
|
||||
// Act
|
||||
cleaner(userWalletId = userWalletId, stakingIds = emptySet())
|
||||
|
||||
// Assert
|
||||
coVerifyOrder(inverse = true) {
|
||||
stakingBalancesStore.clear(userWalletId = any(), stakingIds = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should catch exception from stakingBalancesStore and not throw`() = runTest {
|
||||
// Arrange
|
||||
coEvery { stakingBalancesStore.clear(userWalletId, stakingIds) } throws Exception()
|
||||
|
||||
// Act
|
||||
cleaner(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
|
||||
// Assert
|
||||
coVerifyOrder {
|
||||
stakingBalancesStore.clear(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should handle empty stakingIds`() = runTest {
|
||||
// Act
|
||||
cleaner(userWalletId = userWalletId, stakingIds = emptySet())
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class ClearByCurrencies {
|
||||
|
||||
// Assert
|
||||
coVerifyOrder(inverse = true) {
|
||||
stakingBalancesStore.clear(userWalletId = any(), stakingIds = any())
|
||||
private val cryptoCurrencyFactory = MockCryptoCurrencyFactory()
|
||||
private val coin = cryptoCurrencyFactory.ethereum
|
||||
|
||||
@Test
|
||||
fun `should clear yields balances when called with single currency`() = runTest {
|
||||
// Arrange
|
||||
val stakingId = StakingID(
|
||||
integrationId = "stake_kit_coin_eth",
|
||||
address = "0xabc",
|
||||
)
|
||||
|
||||
coEvery { stakingIdFactory.create(userWalletId, coin) } returns stakingId.right()
|
||||
|
||||
// Act
|
||||
cleaner(userWalletId = userWalletId, currency = coin)
|
||||
|
||||
// Assert
|
||||
coVerifyOrder {
|
||||
stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = coin)
|
||||
stakingBalancesStore.clear(userWalletId = userWalletId, stakingIds = setOf(stakingId))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should handle empty list of currencies`() = runTest {
|
||||
// Act
|
||||
cleaner(userWalletId = userWalletId, currencies = emptyList())
|
||||
|
||||
// Assert
|
||||
coVerifyOrder(inverse = true) {
|
||||
stakingIdFactory.create(userWalletId = any(), cryptoCurrency = any())
|
||||
stakingBalancesStore.clear(userWalletId = any(), stakingIds = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should catch exception from stakingBalancesStore and not throw`() = runTest {
|
||||
// Arrange
|
||||
val stakingId = StakingID(
|
||||
integrationId = "stake_kit_coin_eth",
|
||||
address = "0xabc",
|
||||
)
|
||||
|
||||
coEvery { stakingIdFactory.create(userWalletId, coin) } returns stakingId.right()
|
||||
coEvery {
|
||||
stakingBalancesStore.clear(userWalletId = userWalletId, stakingIds = setOf(stakingId))
|
||||
} throws Exception()
|
||||
|
||||
// Act
|
||||
cleaner(userWalletId = userWalletId, currency = coin)
|
||||
|
||||
// Assert
|
||||
coVerifyOrder {
|
||||
stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = coin)
|
||||
stakingBalancesStore.clear(userWalletId = userWalletId, stakingIds = setOf(stakingId))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue