Updated on 2026-08-14

This commit is contained in:
Tangem 2026-01-26 21:41:59 +07:00
commit eb9eed8d6c
43 changed files with 1296 additions and 131 deletions

View file

@ -4,22 +4,18 @@ import com.tangem.data.account.fetcher.DefaultWalletAccountsFetcher.FetchResult
import com.tangem.data.account.utils.DefaultWalletAccountsResponseFactory
import com.tangem.data.common.currency.UserTokensResponseAccountIdEnricher
import com.tangem.data.common.currency.UserTokensSaver
import com.tangem.data.common.wallet.WalletServerBinder
import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.common.response.ApiResponseError
import com.tangem.datasource.api.common.response.ApiResponseError.HttpException.Code
import com.tangem.datasource.api.common.response.ETAG_HEADER
import com.tangem.datasource.api.common.response.isNetworkError
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.converters.WalletIdBodyConverter
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.api.tangemTech.models.account.GetWalletAccountsResponse
import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
import com.tangem.datasource.api.tangemTech.models.account.toUserTokensResponse
import com.tangem.datasource.local.token.UserTokensResponseStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@ -27,26 +23,21 @@ import javax.inject.Singleton
/**
* Handles errors that occur during the fetching of wallet accounts
*
* @property tangemTechApi API for network requests
* @property userWalletsStore provides access to user wallets storage
* @property userTokensSaver saves user tokens to the storage
* @property userTokensResponseStore provides access to user token responses.
* @property defaultWalletAccountsResponseFactory creates [GetWalletAccountsResponse] from [UserTokensResponse]
* @property dispatchers dispatchers
* @property walletServerBinder binds user wallets on the server
*
* @see DefaultWalletAccountsFetcher
*
[REDACTED_AUTHOR]
*/
@Suppress("LongParameterList")
@Singleton
internal class FetchWalletAccountsErrorHandler @Inject constructor(
private val tangemTechApi: TangemTechApi,
private val userWalletsStore: UserWalletsStore,
private val userTokensSaver: UserTokensSaver,
private val userTokensResponseStore: UserTokensResponseStore,
private val defaultWalletAccountsResponseFactory: DefaultWalletAccountsResponseFactory,
private val dispatchers: CoroutineDispatcherProvider,
private val walletServerBinder: WalletServerBinder,
) {
/**
@ -119,13 +110,7 @@ internal class FetchWalletAccountsErrorHandler @Inject constructor(
*/
private suspend fun createWallet(userWalletId: UserWalletId): String? {
val userWallet = userWalletsStore.getSyncOrNull(key = userWalletId) ?: return null
val creationResponse = withContext(dispatchers.io) {
tangemTechApi.createWallet(
body = WalletIdBodyConverter.convert(userWallet),
)
}
val creationResponse = walletServerBinder.bind(userWalletId)
return if (creationResponse is ApiResponse.Success && creationResponse.code == Code.CREATED) {
creationResponse.headers[ETAG_HEADER]?.firstOrNull()

View file

@ -4,23 +4,22 @@ import com.tangem.data.account.converter.createGetWalletAccountsResponse
import com.tangem.data.account.converter.createWalletAccountDTO
import com.tangem.data.account.utils.DefaultWalletAccountsResponseFactory
import com.tangem.data.common.currency.UserTokensSaver
import com.tangem.data.common.wallet.WalletServerBinder
import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.common.response.ApiResponseError
import com.tangem.datasource.api.common.response.ApiResponseError.HttpException.Code
import com.tangem.datasource.api.common.response.ETAG_HEADER
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.api.tangemTech.models.WalletIdBody
import com.tangem.datasource.api.tangemTech.models.WalletType
import com.tangem.datasource.api.tangemTech.models.account.GetWalletAccountsResponse
import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
import com.tangem.datasource.api.tangemTech.models.account.toUserTokensResponse
import com.tangem.datasource.local.token.UserTokensResponseStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
import io.mockk.*
import io.mockk.clearMocks
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.mockk
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@ -33,18 +32,16 @@ import org.junit.jupiter.api.TestInstance
class FetchWalletAccountsErrorHandlerTest {
private val tangemTechApi: TangemTechApi = mockk()
private val userWalletsStore: UserWalletsStore = mockk()
private val walletServerBinder: WalletServerBinder = mockk()
private val userTokensSaver: UserTokensSaver = mockk(relaxUnitFun = true)
private val userTokensResponseStore: UserTokensResponseStore = mockk(relaxUnitFun = true)
private val defaultWalletAccountsResponseFactory: DefaultWalletAccountsResponseFactory = mockk()
private val handler = FetchWalletAccountsErrorHandler(
tangemTechApi = tangemTechApi,
userWalletsStore = userWalletsStore,
walletServerBinder = walletServerBinder,
userTokensSaver = userTokensSaver,
userTokensResponseStore = userTokensResponseStore,
defaultWalletAccountsResponseFactory = defaultWalletAccountsResponseFactory,
dispatchers = TestingCoroutineDispatcherProvider(),
)
private val pushWalletAccounts: suspend (List<WalletAccountDTO>, String) -> GetWalletAccountsResponse =
@ -55,7 +52,7 @@ class FetchWalletAccountsErrorHandlerTest {
fun setupEach() {
clearMocks(
tangemTechApi,
userWalletsStore,
walletServerBinder,
userTokensSaver,
userTokensResponseStore,
defaultWalletAccountsResponseFactory,
@ -112,22 +109,7 @@ class FetchWalletAccountsErrorHandlerTest {
code = Code.CREATED,
)
val walletName = "Wallet"
val userWallet = mockk<UserWallet.Cold> {
every { this@mockk.walletId } returns userWalletId
every { this@mockk.name } returns walletName
}
coEvery { userWalletsStore.getSyncOrNull(userWalletId) } returns userWallet
coEvery {
tangemTechApi.createWallet(
WalletIdBody(
walletId = userWalletId.stringValue,
name = walletName,
walletType = WalletType.COLD,
),
)
} returns apiResponse
coEvery { walletServerBinder.bind(userWalletId) } returns apiResponse
coEvery { pushWalletAccounts(listOf(accountDTO), eTagValue) } returns savedAccountsResponse
// Act
@ -142,13 +124,7 @@ class FetchWalletAccountsErrorHandlerTest {
// Assert
coVerify {
userTokensSaver.pushWithRetryer(userWalletId, response = savedAccountsResponse.toUserTokensResponse())
tangemTechApi.createWallet(
WalletIdBody(
walletId = userWalletId.stringValue,
name = walletName,
walletType = WalletType.COLD,
),
)
walletServerBinder.bind(userWalletId)
pushWalletAccounts(listOf(accountDTO), eTagValue)
storeWalletAccounts(userWalletId, savedAccountsResponse)
}