Updated on 2026-08-14
This commit is contained in:
parent
c3da795b23
commit
4104aa82f8
5 changed files with 725 additions and 1 deletions
|
|
@ -22,6 +22,7 @@ import com.tangem.domain.tokens.operations.CachedCurrenciesStatusesOperations
|
|||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
||||
import com.tangem.domain.tokens.wallet.WalletBalanceFetcher
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.tap.domain.tokens.DefaultTokensFeatureToggles
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -432,4 +433,26 @@ internal object TokensDomainModule {
|
|||
fun provideGetCryptoCurrenciesUseCase(currenciesRepository: CurrenciesRepository): GetCryptoCurrenciesUseCase {
|
||||
return GetCryptoCurrenciesUseCase(currenciesRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideWalletBalanceFetcher(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
multiWalletCryptoCurrenciesFetcher: MultiWalletCryptoCurrenciesFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): WalletBalanceFetcher {
|
||||
return WalletBalanceFetcher(
|
||||
currenciesRepository = currenciesRepository,
|
||||
multiWalletCryptoCurrenciesFetcher = multiWalletCryptoCurrenciesFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -10,5 +10,6 @@ fun <B> assertEither(actual: Either<Throwable, B>, expected: Either<Throwable, B
|
|||
val expectedError = expected.leftOrNull() ?: error("Actual is Either.Left: $it")
|
||||
|
||||
Truth.assertThat(it::class.java).isEqualTo(expectedError::class.java)
|
||||
Truth.assertThat(it).hasMessageThat().isEqualTo(expectedError.message)
|
||||
}
|
||||
}
|
||||
|
|
@ -86,7 +86,9 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
|
|||
val actual = fetcher(params)
|
||||
|
||||
// Assert
|
||||
val expected = IllegalStateException("${this::class.simpleName} supports only multi-currency wallet").left()
|
||||
val expected = IllegalStateException(
|
||||
"${DefaultMultiWalletCryptoCurrenciesFetcher::class.simpleName} supports only multi-currency wallet",
|
||||
).left()
|
||||
assertEither(actual, expected)
|
||||
|
||||
verifyOrder { userWalletsStore.getSyncStrict(key = params.userWalletId) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,163 @@
|
|||
package com.tangem.domain.tokens.wallet
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.core.flow.FlowFetcher
|
||||
import com.tangem.domain.core.utils.catchOn
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesFetcher
|
||||
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.wallet.implementor.MultiWalletBalanceFetcher
|
||||
import com.tangem.domain.tokens.wallet.implementor.SingleWalletBalanceFetcher
|
||||
import com.tangem.domain.tokens.wallet.implementor.SingleWalletWithTokenBalanceFetcher
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Fetcher of wallet balance by [UserWalletId]
|
||||
*
|
||||
* @property currenciesRepository currencies repository
|
||||
* @property multiWalletBalanceFetcher balance fetcher of multi-currency wallet
|
||||
* @property singleWalletWithTokenBalanceFetcher balance fetcher of single-currency wallet with token
|
||||
* @property singleWalletBalanceFetcher balance fetcher of single-currency wallet
|
||||
* @property multiNetworkStatusFetcher networks statuses fetcher
|
||||
* @property multiQuoteStatusFetcher quotes statuses fetcher
|
||||
* @property multiYieldBalanceFetcher yields balances fetcher
|
||||
* @property dispatchers dispatchers
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
class WalletBalanceFetcher internal constructor(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val multiWalletBalanceFetcher: BaseWalletBalanceFetcher,
|
||||
private val singleWalletWithTokenBalanceFetcher: BaseWalletBalanceFetcher,
|
||||
private val singleWalletBalanceFetcher: BaseWalletBalanceFetcher,
|
||||
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : FlowFetcher<WalletBalanceFetcher.Params> {
|
||||
|
||||
/** Additional constructor without internal dependencies */
|
||||
constructor(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
multiWalletCryptoCurrenciesFetcher: MultiWalletCryptoCurrenciesFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
) : this(
|
||||
currenciesRepository = currenciesRepository,
|
||||
multiWalletBalanceFetcher = MultiWalletBalanceFetcher(
|
||||
multiWalletCryptoCurrenciesFetcher = multiWalletCryptoCurrenciesFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
),
|
||||
singleWalletWithTokenBalanceFetcher = SingleWalletWithTokenBalanceFetcher(
|
||||
currenciesRepository = currenciesRepository,
|
||||
),
|
||||
singleWalletBalanceFetcher = SingleWalletBalanceFetcher(currenciesRepository = currenciesRepository),
|
||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
|
||||
override suspend fun invoke(params: Params) = Either.catchOn(dispatchers.default) {
|
||||
val userWalletId = params.userWalletId
|
||||
val cardTypesResolver = currenciesRepository.getCardTypesResolver(userWalletId = userWalletId)
|
||||
|
||||
val fetcher = when {
|
||||
cardTypesResolver.isMultiwalletAllowed() -> multiWalletBalanceFetcher
|
||||
cardTypesResolver.isSingleWalletWithToken() -> singleWalletWithTokenBalanceFetcher
|
||||
cardTypesResolver.isSingleWallet() -> singleWalletBalanceFetcher
|
||||
else -> error("Unknown type of wallet: $userWalletId")
|
||||
}
|
||||
|
||||
val currencies = fetcher.getCryptoCurrencies(userWalletId = userWalletId).ifEmpty {
|
||||
error("UserWallet doesn't contain crypto-currencies: $userWalletId")
|
||||
}
|
||||
|
||||
fetcher.fetch(userWalletId = userWalletId, currencies = currencies)
|
||||
}
|
||||
|
||||
private suspend fun BaseWalletBalanceFetcher.fetch(userWalletId: UserWalletId, currencies: Set<CryptoCurrency>) {
|
||||
coroutineScope {
|
||||
val results = fetchingSources.map { source ->
|
||||
async {
|
||||
val maybeResult = when (source) {
|
||||
FetchingSource.NETWORK -> fetchNetworks(userWalletId = userWalletId, currencies = currencies)
|
||||
FetchingSource.QUOTE -> fetchQuotes(currencies = currencies)
|
||||
FetchingSource.STAKING -> fetchStaking(userWalletId = userWalletId, currencies = currencies)
|
||||
}
|
||||
|
||||
source to maybeResult
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
|
||||
val errors = results.mapNotNull { (source, maybeResult) ->
|
||||
val error = maybeResult.leftOrNull() ?: return@mapNotNull null
|
||||
|
||||
source to error
|
||||
}
|
||||
|
||||
check(errors.isEmpty()) {
|
||||
val message = "Failed to fetch next sources for $userWalletId:\n" +
|
||||
errors.joinToString(separator = "\n") { "${it.first.name} – ${it.second}" }
|
||||
|
||||
Timber.e(message)
|
||||
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchNetworks(
|
||||
userWalletId: UserWalletId,
|
||||
currencies: Set<CryptoCurrency>,
|
||||
): Either<Throwable, Unit> {
|
||||
return multiNetworkStatusFetcher(
|
||||
params = MultiNetworkStatusFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
networks = currencies.mapTo(destination = hashSetOf(), transform = CryptoCurrency::network),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun fetchQuotes(currencies: Set<CryptoCurrency>): Either<Throwable, Unit> {
|
||||
return multiQuoteStatusFetcher(
|
||||
params = MultiQuoteStatusFetcher.Params(
|
||||
currenciesIds = currencies.mapNotNullTo(destination = hashSetOf(), transform = { it.id.rawCurrencyId }),
|
||||
appCurrencyId = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun fetchStaking(
|
||||
userWalletId: UserWalletId,
|
||||
currencies: Set<CryptoCurrency>,
|
||||
): Either<Throwable, Unit> {
|
||||
return multiYieldBalanceFetcher(
|
||||
params = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyIdWithNetworkMap = currencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Params of [WalletBalanceFetcher]
|
||||
*
|
||||
* @property userWalletId user wallet id
|
||||
*/
|
||||
data class Params(val userWalletId: UserWalletId)
|
||||
}
|
||||
|
|
@ -0,0 +1,535 @@
|
|||
package com.tangem.domain.tokens.wallet
|
||||
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
||||
import com.tangem.common.test.utils.assertEither
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.wallet.FetchingSource.*
|
||||
import com.tangem.domain.tokens.wallet.implementor.MultiWalletBalanceFetcher
|
||||
import com.tangem.domain.tokens.wallet.implementor.SingleWalletBalanceFetcher
|
||||
import com.tangem.domain.tokens.wallet.implementor.SingleWalletWithTokenBalanceFetcher
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.*
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class WalletBalanceFetcherTest {
|
||||
|
||||
private val cryptoCurrencyFactory = MockCryptoCurrencyFactory()
|
||||
|
||||
private val currenciesRepository: CurrenciesRepository = mockk()
|
||||
private val multiWalletBalanceFetcher: MultiWalletBalanceFetcher = mockk()
|
||||
private val singleWalletWithTokenBalanceFetcher: SingleWalletWithTokenBalanceFetcher = mockk()
|
||||
private val singleWalletBalanceFetcher: SingleWalletBalanceFetcher = mockk()
|
||||
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher = mockk()
|
||||
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher = mockk()
|
||||
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher = mockk()
|
||||
|
||||
private val fetcher = WalletBalanceFetcher(
|
||||
currenciesRepository = currenciesRepository,
|
||||
multiWalletBalanceFetcher = multiWalletBalanceFetcher,
|
||||
singleWalletWithTokenBalanceFetcher = singleWalletWithTokenBalanceFetcher,
|
||||
singleWalletBalanceFetcher = singleWalletBalanceFetcher,
|
||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
)
|
||||
|
||||
@BeforeEach
|
||||
fun resetMocks() {
|
||||
clearMocks(
|
||||
currenciesRepository,
|
||||
multiWalletBalanceFetcher,
|
||||
singleWalletWithTokenBalanceFetcher,
|
||||
singleWalletBalanceFetcher,
|
||||
multiNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if getCardTypesResolver THROWS EXCEPTION`() = runTest {
|
||||
// Arrange
|
||||
val exception = IllegalStateException("Error")
|
||||
every { currenciesRepository.getCardTypesResolver(userWalletId = userWalletId) } throws exception
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params = WalletBalanceFetcher.Params(userWalletId = userWalletId))
|
||||
|
||||
// Assert
|
||||
val expected = exception.left()
|
||||
assertEither(actual, expected)
|
||||
|
||||
verifyOrder { currenciesRepository.getCardTypesResolver(userWalletId = userWalletId) }
|
||||
|
||||
coVerify(inverse = true) {
|
||||
multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
singleWalletWithTokenBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
singleWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
multiNetworkStatusFetcher(params = any())
|
||||
multiQuoteStatusFetcher(params = any())
|
||||
multiYieldBalanceFetcher(params = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if getCardTypesResolver cannot resolve wallet type`() = runTest {
|
||||
// Arrange
|
||||
val cardTypesResolver = mockk<CardTypesResolver> {
|
||||
every { isMultiwalletAllowed() } returns false
|
||||
every { isSingleWalletWithToken() } returns false
|
||||
every { isSingleWallet() } returns false
|
||||
}
|
||||
|
||||
every { currenciesRepository.getCardTypesResolver(userWalletId = userWalletId) } returns cardTypesResolver
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params = WalletBalanceFetcher.Params(userWalletId = userWalletId))
|
||||
|
||||
// Assert
|
||||
val expected = IllegalStateException("Unknown type of wallet: $userWalletId").left()
|
||||
assertEither(actual, expected)
|
||||
|
||||
verifyOrder { currenciesRepository.getCardTypesResolver(userWalletId = userWalletId) }
|
||||
|
||||
coVerify(inverse = true) {
|
||||
multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
singleWalletWithTokenBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
singleWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
multiNetworkStatusFetcher(params = any())
|
||||
multiQuoteStatusFetcher(params = any())
|
||||
multiYieldBalanceFetcher(params = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if getCryptoCurrencies THROWS EXCEPTION`() = runTest {
|
||||
// Arrange
|
||||
val cardTypesResolver = mockk<CardTypesResolver> {
|
||||
every { isMultiwalletAllowed() } returns true
|
||||
}
|
||||
|
||||
val exception = IllegalStateException("Error")
|
||||
|
||||
every { currenciesRepository.getCardTypesResolver(userWalletId = userWalletId) } returns cardTypesResolver
|
||||
coEvery { multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId) } throws exception
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params = WalletBalanceFetcher.Params(userWalletId = userWalletId))
|
||||
|
||||
// Assert
|
||||
val expected = exception.left()
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
currenciesRepository.getCardTypesResolver(userWalletId = userWalletId)
|
||||
multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
singleWalletWithTokenBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
singleWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
multiNetworkStatusFetcher(params = any())
|
||||
multiQuoteStatusFetcher(params = any())
|
||||
multiYieldBalanceFetcher(params = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if getCryptoCurrencies RETURNS EMPTY SET`() = runTest {
|
||||
// Arrange
|
||||
val cardTypesResolver = mockk<CardTypesResolver> {
|
||||
every { isMultiwalletAllowed() } returns true
|
||||
}
|
||||
|
||||
every { currenciesRepository.getCardTypesResolver(userWalletId = userWalletId) } returns cardTypesResolver
|
||||
coEvery { multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId) } returns emptySet()
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params = WalletBalanceFetcher.Params(userWalletId = userWalletId))
|
||||
|
||||
// Assert
|
||||
val expected = IllegalStateException("UserWallet doesn't contain crypto-currencies: $userWalletId").left()
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
currenciesRepository.getCardTypesResolver(userWalletId = userWalletId)
|
||||
multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
singleWalletWithTokenBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
singleWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
multiNetworkStatusFetcher(params = any())
|
||||
multiQuoteStatusFetcher(params = any())
|
||||
multiYieldBalanceFetcher(params = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if fetchNetworks RETURNS LEFT`() = runTest {
|
||||
// Arrange
|
||||
val cardTypesResolver = mockk<CardTypesResolver> {
|
||||
every { isMultiwalletAllowed() } returns true
|
||||
}
|
||||
|
||||
val currencies = cryptoCurrencyFactory.ethereumAndStellar.toSet()
|
||||
val networkStatusFetcherParams = MultiNetworkStatusFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
networks = currencies.mapTo(destination = hashSetOf(), transform = CryptoCurrency::network),
|
||||
)
|
||||
|
||||
val exception = IllegalStateException("Error")
|
||||
|
||||
every { currenciesRepository.getCardTypesResolver(userWalletId = userWalletId) } returns cardTypesResolver
|
||||
coEvery { multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId) } returns currencies
|
||||
every { multiWalletBalanceFetcher.fetchingSources } returns setOf(NETWORK)
|
||||
coEvery { multiNetworkStatusFetcher(params = networkStatusFetcherParams) } returns exception.left()
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params = WalletBalanceFetcher.Params(userWalletId = userWalletId))
|
||||
|
||||
// Assert
|
||||
val expected = IllegalStateException(
|
||||
"Failed to fetch next sources for UserWalletId(011...011):\n" +
|
||||
"NETWORK – java.lang.IllegalStateException: Error",
|
||||
).left()
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
currenciesRepository.getCardTypesResolver(userWalletId = userWalletId)
|
||||
multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId)
|
||||
multiWalletBalanceFetcher.fetchingSources
|
||||
multiNetworkStatusFetcher(params = networkStatusFetcherParams)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
singleWalletWithTokenBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
singleWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
multiQuoteStatusFetcher(params = any())
|
||||
multiYieldBalanceFetcher(params = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if fetchQuotes RETURNS LEFT`() = runTest {
|
||||
// Arrange
|
||||
val cardTypesResolver = mockk<CardTypesResolver> {
|
||||
every { isMultiwalletAllowed() } returns true
|
||||
}
|
||||
|
||||
val currencies = cryptoCurrencyFactory.ethereumAndStellar.toSet()
|
||||
val quoteStatusFetcherParams = MultiQuoteStatusFetcher.Params(
|
||||
currenciesIds = currencies.mapNotNullTo(destination = hashSetOf(), transform = { it.id.rawCurrencyId }),
|
||||
appCurrencyId = null,
|
||||
)
|
||||
|
||||
val exception = IllegalStateException("Error")
|
||||
|
||||
every { currenciesRepository.getCardTypesResolver(userWalletId = userWalletId) } returns cardTypesResolver
|
||||
coEvery { multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId) } returns currencies
|
||||
every { multiWalletBalanceFetcher.fetchingSources } returns setOf(QUOTE)
|
||||
coEvery { multiQuoteStatusFetcher(params = quoteStatusFetcherParams) } returns exception.left()
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params = WalletBalanceFetcher.Params(userWalletId = userWalletId))
|
||||
|
||||
// Assert
|
||||
val expected = IllegalStateException(
|
||||
"Failed to fetch next sources for UserWalletId(011...011):\n" +
|
||||
"QUOTE – java.lang.IllegalStateException: Error",
|
||||
).left()
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
currenciesRepository.getCardTypesResolver(userWalletId = userWalletId)
|
||||
multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId)
|
||||
multiWalletBalanceFetcher.fetchingSources
|
||||
multiQuoteStatusFetcher(params = quoteStatusFetcherParams)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
singleWalletWithTokenBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
singleWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
multiNetworkStatusFetcher(params = any())
|
||||
multiYieldBalanceFetcher(params = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if fetchStaking RETURNS LEFT`() = runTest {
|
||||
// Arrange
|
||||
val cardTypesResolver = mockk<CardTypesResolver> {
|
||||
every { isMultiwalletAllowed() } returns true
|
||||
}
|
||||
|
||||
val currencies = cryptoCurrencyFactory.ethereumAndStellar.toSet()
|
||||
val yieldBalanceFetcherParams = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyIdWithNetworkMap = currencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
)
|
||||
|
||||
val exception = IllegalStateException("Error")
|
||||
|
||||
every { currenciesRepository.getCardTypesResolver(userWalletId = userWalletId) } returns cardTypesResolver
|
||||
coEvery { multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId) } returns currencies
|
||||
every { multiWalletBalanceFetcher.fetchingSources } returns setOf(STAKING)
|
||||
coEvery { multiYieldBalanceFetcher(params = yieldBalanceFetcherParams) } returns exception.left()
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params = WalletBalanceFetcher.Params(userWalletId = userWalletId))
|
||||
|
||||
// Assert
|
||||
val expected = IllegalStateException(
|
||||
"Failed to fetch next sources for UserWalletId(011...011):\n" +
|
||||
"STAKING – java.lang.IllegalStateException: Error",
|
||||
).left()
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
currenciesRepository.getCardTypesResolver(userWalletId = userWalletId)
|
||||
multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId)
|
||||
multiWalletBalanceFetcher.fetchingSources
|
||||
multiYieldBalanceFetcher(params = yieldBalanceFetcherParams)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
singleWalletWithTokenBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
singleWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
multiNetworkStatusFetcher(params = any())
|
||||
multiQuoteStatusFetcher(params = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if all fetching sources RETURNS LEFT`() = runTest {
|
||||
// Arrange
|
||||
val cardTypesResolver = mockk<CardTypesResolver> {
|
||||
every { isMultiwalletAllowed() } returns true
|
||||
}
|
||||
|
||||
val currencies = cryptoCurrencyFactory.ethereumAndStellar.toSet()
|
||||
|
||||
val networkStatusFetcherParams = MultiNetworkStatusFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
networks = currencies.mapTo(destination = hashSetOf(), transform = CryptoCurrency::network),
|
||||
)
|
||||
|
||||
val quoteStatusFetcherParams = MultiQuoteStatusFetcher.Params(
|
||||
currenciesIds = currencies.mapNotNullTo(destination = hashSetOf(), transform = { it.id.rawCurrencyId }),
|
||||
appCurrencyId = null,
|
||||
)
|
||||
|
||||
val yieldBalanceFetcherParams = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyIdWithNetworkMap = currencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
)
|
||||
|
||||
val exception = IllegalStateException("Error")
|
||||
|
||||
every { currenciesRepository.getCardTypesResolver(userWalletId = userWalletId) } returns cardTypesResolver
|
||||
coEvery { multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId) } returns currencies
|
||||
every { multiWalletBalanceFetcher.fetchingSources } returns setOf(NETWORK, QUOTE, STAKING)
|
||||
coEvery { multiNetworkStatusFetcher(params = networkStatusFetcherParams) } returns exception.left()
|
||||
coEvery { multiQuoteStatusFetcher(params = quoteStatusFetcherParams) } returns exception.left()
|
||||
coEvery { multiYieldBalanceFetcher(params = yieldBalanceFetcherParams) } returns exception.left()
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params = WalletBalanceFetcher.Params(userWalletId = userWalletId))
|
||||
|
||||
// Assert
|
||||
val expected = IllegalStateException(
|
||||
"Failed to fetch next sources for UserWalletId(011...011):\n" +
|
||||
"NETWORK – java.lang.IllegalStateException: Error\n" +
|
||||
"QUOTE – java.lang.IllegalStateException: Error\n" +
|
||||
"STAKING – java.lang.IllegalStateException: Error",
|
||||
).left()
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
currenciesRepository.getCardTypesResolver(userWalletId = userWalletId)
|
||||
multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId)
|
||||
multiWalletBalanceFetcher.fetchingSources
|
||||
multiNetworkStatusFetcher(params = networkStatusFetcherParams)
|
||||
multiQuoteStatusFetcher(params = quoteStatusFetcherParams)
|
||||
multiYieldBalanceFetcher(params = yieldBalanceFetcherParams)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
singleWalletWithTokenBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
singleWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch successfully for multi-currency wallet`() = runTest {
|
||||
// Arrange
|
||||
val cardTypesResolver = mockk<CardTypesResolver> {
|
||||
every { isMultiwalletAllowed() } returns true
|
||||
}
|
||||
|
||||
val currencies = cryptoCurrencyFactory.ethereumAndStellar.toSet()
|
||||
|
||||
val networkStatusFetcherParams = MultiNetworkStatusFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
networks = currencies.mapTo(destination = hashSetOf(), transform = CryptoCurrency::network),
|
||||
)
|
||||
|
||||
val quoteStatusFetcherParams = MultiQuoteStatusFetcher.Params(
|
||||
currenciesIds = currencies.mapNotNullTo(destination = hashSetOf(), transform = { it.id.rawCurrencyId }),
|
||||
appCurrencyId = null,
|
||||
)
|
||||
|
||||
val yieldBalanceFetcherParams = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
currencyIdWithNetworkMap = currencies.associateTo(hashMapOf()) { it.id to it.network },
|
||||
)
|
||||
|
||||
every { currenciesRepository.getCardTypesResolver(userWalletId = userWalletId) } returns cardTypesResolver
|
||||
coEvery { multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId) } returns currencies
|
||||
every { multiWalletBalanceFetcher.fetchingSources } returns setOf(NETWORK, QUOTE, STAKING)
|
||||
coEvery { multiNetworkStatusFetcher(params = networkStatusFetcherParams) } returns Unit.right()
|
||||
coEvery { multiQuoteStatusFetcher(params = quoteStatusFetcherParams) } returns Unit.right()
|
||||
coEvery { multiYieldBalanceFetcher(params = yieldBalanceFetcherParams) } returns Unit.right()
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params = WalletBalanceFetcher.Params(userWalletId = userWalletId))
|
||||
|
||||
// Assert
|
||||
val expected = Unit.right()
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
currenciesRepository.getCardTypesResolver(userWalletId = userWalletId)
|
||||
multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId)
|
||||
multiWalletBalanceFetcher.fetchingSources
|
||||
multiNetworkStatusFetcher(params = networkStatusFetcherParams)
|
||||
multiQuoteStatusFetcher(params = quoteStatusFetcherParams)
|
||||
multiYieldBalanceFetcher(params = yieldBalanceFetcherParams)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
singleWalletWithTokenBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
singleWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch successfully for single-currency with token wallet`() = runTest {
|
||||
// Arrange
|
||||
val cardTypesResolver = mockk<CardTypesResolver> {
|
||||
every { isMultiwalletAllowed() } returns false
|
||||
every { isSingleWalletWithToken() } returns true
|
||||
}
|
||||
|
||||
val currencies = cryptoCurrencyFactory.ethereumAndStellar.toSet()
|
||||
|
||||
val networkStatusFetcherParams = MultiNetworkStatusFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
networks = currencies.mapTo(destination = hashSetOf(), transform = CryptoCurrency::network),
|
||||
)
|
||||
|
||||
val quoteStatusFetcherParams = MultiQuoteStatusFetcher.Params(
|
||||
currenciesIds = currencies.mapNotNullTo(destination = hashSetOf(), transform = { it.id.rawCurrencyId }),
|
||||
appCurrencyId = null,
|
||||
)
|
||||
|
||||
every { currenciesRepository.getCardTypesResolver(userWalletId = userWalletId) } returns cardTypesResolver
|
||||
coEvery {
|
||||
singleWalletWithTokenBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId)
|
||||
} returns currencies
|
||||
every { singleWalletWithTokenBalanceFetcher.fetchingSources } returns setOf(NETWORK, QUOTE)
|
||||
coEvery { multiNetworkStatusFetcher(params = networkStatusFetcherParams) } returns Unit.right()
|
||||
coEvery { multiQuoteStatusFetcher(params = quoteStatusFetcherParams) } returns Unit.right()
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params = WalletBalanceFetcher.Params(userWalletId = userWalletId))
|
||||
|
||||
// Assert
|
||||
val expected = Unit.right()
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
currenciesRepository.getCardTypesResolver(userWalletId = userWalletId)
|
||||
singleWalletWithTokenBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId)
|
||||
singleWalletWithTokenBalanceFetcher.fetchingSources
|
||||
multiNetworkStatusFetcher(params = networkStatusFetcherParams)
|
||||
multiQuoteStatusFetcher(params = quoteStatusFetcherParams)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
singleWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
multiYieldBalanceFetcher(params = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch successfully for single-currency wallet`() = runTest {
|
||||
// Arrange
|
||||
val cardTypesResolver = mockk<CardTypesResolver> {
|
||||
every { isMultiwalletAllowed() } returns false
|
||||
every { isSingleWalletWithToken() } returns false
|
||||
every { isSingleWallet() } returns true
|
||||
}
|
||||
|
||||
val currencies = cryptoCurrencyFactory.ethereumAndStellar.toSet()
|
||||
|
||||
val networkStatusFetcherParams = MultiNetworkStatusFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
networks = currencies.mapTo(destination = hashSetOf(), transform = CryptoCurrency::network),
|
||||
)
|
||||
|
||||
val quoteStatusFetcherParams = MultiQuoteStatusFetcher.Params(
|
||||
currenciesIds = currencies.mapNotNullTo(destination = hashSetOf(), transform = { it.id.rawCurrencyId }),
|
||||
appCurrencyId = null,
|
||||
)
|
||||
|
||||
every { currenciesRepository.getCardTypesResolver(userWalletId = userWalletId) } returns cardTypesResolver
|
||||
coEvery { singleWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId) } returns currencies
|
||||
every { singleWalletBalanceFetcher.fetchingSources } returns setOf(NETWORK, QUOTE)
|
||||
coEvery { multiNetworkStatusFetcher(params = networkStatusFetcherParams) } returns Unit.right()
|
||||
coEvery { multiQuoteStatusFetcher(params = quoteStatusFetcherParams) } returns Unit.right()
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params = WalletBalanceFetcher.Params(userWalletId = userWalletId))
|
||||
|
||||
// Assert
|
||||
val expected = Unit.right()
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
currenciesRepository.getCardTypesResolver(userWalletId = userWalletId)
|
||||
singleWalletBalanceFetcher.getCryptoCurrencies(userWalletId = userWalletId)
|
||||
singleWalletBalanceFetcher.fetchingSources
|
||||
multiNetworkStatusFetcher(params = networkStatusFetcherParams)
|
||||
multiQuoteStatusFetcher(params = quoteStatusFetcherParams)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
multiWalletBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
singleWalletWithTokenBalanceFetcher.getCryptoCurrencies(userWalletId = any())
|
||||
multiYieldBalanceFetcher(params = any())
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
val userWalletId = UserWalletId("011")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue