Updated on 2026-08-14
This commit is contained in:
parent
78a173a140
commit
2a2e0b3323
6 changed files with 123 additions and 45 deletions
|
|
@ -19,6 +19,7 @@ import com.tangem.domain.demo.DemoConfig
|
|||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.model.NetworkStatus
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -76,7 +77,16 @@ internal class DefaultSingleNetworkStatusFetcher @Inject constructor(
|
|||
currencies = networkCurrencies.toSet(),
|
||||
)
|
||||
|
||||
networksStatusesStore.storeActual(userWalletId = params.userWalletId, value = status)
|
||||
val statusValue = status.value
|
||||
if (statusValue is NetworkStatus.Unreachable) {
|
||||
networksStatusesStore.storeError(
|
||||
userWalletId = params.userWalletId,
|
||||
network = params.network,
|
||||
value = statusValue,
|
||||
)
|
||||
} else {
|
||||
networksStatusesStore.storeSuccess(userWalletId = params.userWalletId, value = status)
|
||||
}
|
||||
}
|
||||
.onLeft {
|
||||
Timber.e("Failed to fetch network status for $params: $it")
|
||||
|
|
|
|||
|
|
@ -70,9 +70,19 @@ internal class DefaultNetworksStatusesStoreV2(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun storeActual(userWalletId: UserWalletId, value: NetworkStatus) {
|
||||
override suspend fun storeSuccess(userWalletId: UserWalletId, value: NetworkStatus) {
|
||||
if (value.value is NetworkStatus.Unreachable) {
|
||||
val message = "Use storeError method to save unreachable status"
|
||||
Timber.d(message)
|
||||
|
||||
error(message)
|
||||
}
|
||||
|
||||
if (value.value.source != StatusSource.ACTUAL) {
|
||||
error("Method storeActual can be called only with StatusSource.ACTUAL")
|
||||
val message = "Method storeActual can be called only with StatusSource.ACTUAL"
|
||||
Timber.d(message)
|
||||
|
||||
error(message)
|
||||
}
|
||||
|
||||
coroutineScope {
|
||||
|
|
@ -81,11 +91,14 @@ internal class DefaultNetworksStatusesStoreV2(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun storeError(userWalletId: UserWalletId, network: Network) {
|
||||
override suspend fun storeError(userWalletId: UserWalletId, network: Network, value: NetworkStatus.Unreachable?) {
|
||||
updateInRuntime(
|
||||
userWalletId = userWalletId,
|
||||
networks = setOf(network),
|
||||
ifNotFound = ::createUnreachableStatus,
|
||||
ifNotFound = { id ->
|
||||
value?.let { SimpleNetworkStatus(id = id, value = value) }
|
||||
?: createUnreachableStatus(id = id)
|
||||
},
|
||||
update = { status ->
|
||||
status.copy(value = status.value.copySealed(source = StatusSource.ONLY_CACHE))
|
||||
},
|
||||
|
|
|
|||
|
|
@ -18,9 +18,13 @@ internal interface NetworksStatusesStoreV2 {
|
|||
/** Refresh statuses of [networks] by [userWalletId] */
|
||||
suspend fun refresh(userWalletId: UserWalletId, networks: Set<Network>)
|
||||
|
||||
/** Store actual [NetworkStatus] by [userWalletId] */
|
||||
suspend fun storeActual(userWalletId: UserWalletId, value: NetworkStatus)
|
||||
/** Store success [value] by [userWalletId]. If status's value is unreachable, throws exception */
|
||||
@Throws
|
||||
suspend fun storeSuccess(userWalletId: UserWalletId, value: NetworkStatus)
|
||||
|
||||
/** Store error by [userWalletId] and [network] */
|
||||
suspend fun storeError(userWalletId: UserWalletId, network: Network)
|
||||
/**
|
||||
* Store error [value] by [userWalletId] and [network].
|
||||
* If [value] is null, default unreachable status will be stored.
|
||||
*/
|
||||
suspend fun storeError(userWalletId: UserWalletId, network: Network, value: NetworkStatus.Unreachable? = null)
|
||||
}
|
||||
|
|
@ -52,7 +52,7 @@ internal class DefaultSingleNetworkStatusFetcherTest {
|
|||
networksStatusesStore.refresh(userWalletId = userWalletId, network = network)
|
||||
userWalletsStore.getSyncStrict(key = userWalletId)
|
||||
walletManagersFacade.update(userWalletId, network, emptySet())
|
||||
networksStatusesStore.storeActual(
|
||||
networksStatusesStore.storeSuccess(
|
||||
userWalletId = userWalletId,
|
||||
value = NetworkStatus(network, NetworkStatus.MissedDerivation),
|
||||
)
|
||||
|
|
@ -82,7 +82,7 @@ internal class DefaultSingleNetworkStatusFetcherTest {
|
|||
|
||||
coVerify(inverse = true) {
|
||||
walletManagersFacade.update(userWalletId = any(), network = any(), extraTokens = any())
|
||||
networksStatusesStore.storeActual(userWalletId = any(), value = any())
|
||||
networksStatusesStore.storeSuccess(userWalletId = any(), value = any())
|
||||
}
|
||||
|
||||
Truth.assertThat(actual.isLeft()).isTrue()
|
||||
|
|
@ -105,7 +105,7 @@ internal class DefaultSingleNetworkStatusFetcherTest {
|
|||
coVerifyOrder {
|
||||
userWalletsStore.getSyncStrict(key = userWalletId)
|
||||
walletManagersFacade.update(userWalletId, network, emptySet())
|
||||
networksStatusesStore.storeActual(
|
||||
networksStatusesStore.storeSuccess(
|
||||
userWalletId = userWalletId,
|
||||
value = NetworkStatus(network, NetworkStatus.MissedDerivation),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ internal class NetworkStatusesStoreUpdateMethodsTest {
|
|||
|
||||
@Test
|
||||
fun `refresh the single network if runtime store contains status with this network`() = runTest {
|
||||
val status = MockNetworkStatusFactory.createVerified().toSimple()
|
||||
val status = MockNetworkStatusFactory.createVerified(network).toSimple()
|
||||
|
||||
runtimeStore.store(
|
||||
value = mapOf(userWalletId.stringValue to setOf(status)),
|
||||
|
|
@ -98,41 +98,50 @@ internal class NetworkStatusesStoreUpdateMethodsTest {
|
|||
val expectedErrorMessage = "Method storeActual can be called only with StatusSource.ACTUAL"
|
||||
|
||||
// #1: StatusSource.ACTUAL
|
||||
val status = MockNetworkStatusFactory.createVerified().copy(
|
||||
value = MockNetworkStatusFactory.createVerified().value.copySealed(source = StatusSource.ACTUAL),
|
||||
val status = MockNetworkStatusFactory.createVerified(network).copy(
|
||||
value = MockNetworkStatusFactory.createVerified(network).value.copySealed(source = StatusSource.ACTUAL),
|
||||
)
|
||||
|
||||
val actual = runCatching { store.storeActual(userWalletId, status) }
|
||||
val actual = runCatching { store.storeSuccess(userWalletId, status) }
|
||||
|
||||
val runtimeExpected = mapOf(userWalletId.stringValue to setOf(status.toSimple()))
|
||||
val persistenceExpected = mapOf(userWalletId.stringValue to setOf(status.toDataModel()!!))
|
||||
|
||||
Truth.assertThat(actual.isSuccess).isTrue()
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(runtimeExpected)
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(persistenceExpected)
|
||||
|
||||
// #2: StatusSource.CACHE
|
||||
val cacheStatus = MockNetworkStatusFactory.createVerified().copy(
|
||||
value = MockNetworkStatusFactory.createVerified().value.copySealed(source = StatusSource.CACHE),
|
||||
val cacheStatus = MockNetworkStatusFactory.createVerified(network).copy(
|
||||
value = MockNetworkStatusFactory.createVerified(network).value.copySealed(source = StatusSource.CACHE),
|
||||
)
|
||||
|
||||
val cacheActual = runCatching { store.storeActual(userWalletId, cacheStatus) }
|
||||
val cacheActual = runCatching { store.storeSuccess(userWalletId, cacheStatus) }
|
||||
|
||||
Truth.assertThat(cacheActual.isFailure).isTrue()
|
||||
Truth.assertThat(cacheActual.exceptionOrNull()).isInstanceOf(IllegalStateException::class.java)
|
||||
Truth.assertThat(cacheActual.exceptionOrNull()).hasMessageThat().isEqualTo(expectedErrorMessage)
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(runtimeExpected)
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(persistenceExpected)
|
||||
|
||||
// #3: StatusSource.ONLY_CACHE
|
||||
val onlyCacheStatus = MockNetworkStatusFactory.createVerified().copy(
|
||||
value = MockNetworkStatusFactory.createVerified().value.copySealed(source = StatusSource.ONLY_CACHE),
|
||||
val onlyCacheStatus = MockNetworkStatusFactory.createVerified(network).copy(
|
||||
value = MockNetworkStatusFactory.createVerified(network).value.copySealed(source = StatusSource.ONLY_CACHE),
|
||||
)
|
||||
|
||||
val onlyCacheActual = runCatching { store.storeActual(userWalletId, onlyCacheStatus) }
|
||||
val onlyCacheActual = runCatching { store.storeSuccess(userWalletId, onlyCacheStatus) }
|
||||
|
||||
Truth.assertThat(onlyCacheActual.isFailure).isTrue()
|
||||
Truth.assertThat(onlyCacheActual.exceptionOrNull()).isInstanceOf(IllegalStateException::class.java)
|
||||
Truth.assertThat(onlyCacheActual.exceptionOrNull()).hasMessageThat().isEqualTo(expectedErrorMessage)
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(runtimeExpected)
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(persistenceExpected)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `store actual if runtime and cache stores contain status with this network`() = runTest {
|
||||
val prevStatus = MockNetworkStatusFactory.createVerified().copy(
|
||||
value = MockNetworkStatusFactory.createVerified().value.copySealed(source = StatusSource.ONLY_CACHE),
|
||||
val prevStatus = MockNetworkStatusFactory.createVerified(network).copy(
|
||||
value = MockNetworkStatusFactory.createVerified(network).value.copySealed(source = StatusSource.ONLY_CACHE),
|
||||
)
|
||||
|
||||
runtimeStore.store(
|
||||
|
|
@ -145,11 +154,11 @@ internal class NetworkStatusesStoreUpdateMethodsTest {
|
|||
}
|
||||
}
|
||||
|
||||
val newStatus = MockNetworkStatusFactory.createVerified().copy(
|
||||
value = MockNetworkStatusFactory.createVerified().value.copySealed(source = StatusSource.ACTUAL),
|
||||
val newStatus = MockNetworkStatusFactory.createVerified(network).copy(
|
||||
value = MockNetworkStatusFactory.createVerified(network).value.copySealed(source = StatusSource.ACTUAL),
|
||||
)
|
||||
|
||||
store.storeActual(userWalletId, newStatus)
|
||||
store.storeSuccess(userWalletId, newStatus)
|
||||
|
||||
val runtimeExpected = mapOf(
|
||||
userWalletId.stringValue to setOf(newStatus.toSimple()),
|
||||
|
|
@ -165,7 +174,7 @@ internal class NetworkStatusesStoreUpdateMethodsTest {
|
|||
|
||||
@Test
|
||||
fun `store actual unreachable status if cache store contains verified status`() = runTest {
|
||||
val prevStatus = MockNetworkStatusFactory.createVerified()
|
||||
val prevStatus = MockNetworkStatusFactory.createVerified(network)
|
||||
|
||||
runtimeStore.store(
|
||||
value = mapOf(userWalletId.stringValue to setOf(prevStatus.toSimple())),
|
||||
|
|
@ -177,18 +186,17 @@ internal class NetworkStatusesStoreUpdateMethodsTest {
|
|||
}
|
||||
}
|
||||
|
||||
val newStatus = MockNetworkStatusFactory.createUnreachable()
|
||||
val newStatus = MockNetworkStatusFactory.createUnreachable(network)
|
||||
|
||||
store.storeActual(userWalletId, newStatus)
|
||||
val actual = runCatching { store.storeSuccess(userWalletId, newStatus) }
|
||||
|
||||
val runtimeExpected = mapOf(
|
||||
userWalletId.stringValue to setOf(newStatus.toSimple()),
|
||||
)
|
||||
|
||||
val persistenceExpected = mapOf(
|
||||
userWalletId.stringValue to setOf(prevStatus.toDataModel()!!),
|
||||
)
|
||||
val expectedErrorMessage = "Use storeError method to save unreachable status"
|
||||
val runtimeExpected = mapOf(userWalletId.stringValue to setOf(prevStatus.toSimple()))
|
||||
val persistenceExpected = mapOf(userWalletId.stringValue to setOf(prevStatus.toDataModel()!!))
|
||||
|
||||
Truth.assertThat(actual.isFailure).isTrue()
|
||||
Truth.assertThat(actual.exceptionOrNull()).isInstanceOf(IllegalStateException::class.java)
|
||||
Truth.assertThat(actual.exceptionOrNull()).hasMessageThat().isEqualTo(expectedErrorMessage)
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(runtimeExpected)
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(persistenceExpected)
|
||||
}
|
||||
|
|
@ -212,7 +220,7 @@ internal class NetworkStatusesStoreUpdateMethodsTest {
|
|||
|
||||
@Test
|
||||
fun `store error if runtime store contains status with this network`() = runTest {
|
||||
val status = MockNetworkStatusFactory.createVerified().toSimple()
|
||||
val status = MockNetworkStatusFactory.createVerified(network).toSimple()
|
||||
|
||||
runtimeStore.store(
|
||||
value = mapOf(userWalletId.stringValue to setOf(status)),
|
||||
|
|
@ -230,6 +238,48 @@ internal class NetworkStatusesStoreUpdateMethodsTest {
|
|||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<NetworkStatusDM>>())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `store error if runtime store is empty and unreachable status was passed`() = runTest {
|
||||
val status = MockNetworkStatusFactory.createUnreachable(network)
|
||||
|
||||
store.storeError(
|
||||
userWalletId = userWalletId,
|
||||
network = network,
|
||||
value = status.value as NetworkStatus.Unreachable,
|
||||
)
|
||||
|
||||
val runtimeExpected = mapOf(
|
||||
userWalletId.stringValue to setOf(status.toSimple()),
|
||||
)
|
||||
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(runtimeExpected)
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<NetworkStatusDM>>())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `store error if runtime store contains status with this network and unreachable status was passed`() = runTest {
|
||||
val status = MockNetworkStatusFactory.createVerified(network)
|
||||
|
||||
runtimeStore.store(
|
||||
value = mapOf(userWalletId.stringValue to setOf(status.toSimple())),
|
||||
)
|
||||
|
||||
store.storeError(
|
||||
userWalletId = userWalletId,
|
||||
network = network,
|
||||
value = MockNetworkStatusFactory.createUnreachable(network).value as NetworkStatus.Unreachable,
|
||||
)
|
||||
|
||||
val runtimeExpected = mapOf(
|
||||
userWalletId.stringValue to setOf(
|
||||
status.copy(value = status.value.copySealed(source = StatusSource.ONLY_CACHE)).toSimple(),
|
||||
),
|
||||
)
|
||||
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(runtimeExpected)
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<NetworkStatusDM>>())
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
val userWalletId = UserWalletId(stringValue = "011")
|
||||
|
|
|
|||
|
|
@ -33,15 +33,16 @@ internal class StoreActualNetworkStatusTest(private val model: Model) {
|
|||
|
||||
@Test
|
||||
fun `store actual`() = runTest {
|
||||
store.storeActual(userWalletId = userWalletId, value = model.status)
|
||||
val actual = runCatching { store.storeSuccess(userWalletId = userWalletId, value = model.status) }
|
||||
|
||||
Truth.assertThat(actual.isSuccess).isEqualTo(model.isSuccess)
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(model.runtimeExpected)
|
||||
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(model.persistenceExpected)
|
||||
}
|
||||
|
||||
data class Model(
|
||||
val status: NetworkStatus,
|
||||
val isSuccess: Boolean,
|
||||
val runtimeExpected: Map<String, Set<SimpleNetworkStatus>>,
|
||||
val persistenceExpected: WalletIdWithStatusDM,
|
||||
)
|
||||
|
|
@ -56,6 +57,7 @@ internal class StoreActualNetworkStatusTest(private val model: Model) {
|
|||
return listOf(
|
||||
Model(
|
||||
status = MockNetworkStatusFactory.createVerified(),
|
||||
isSuccess = true,
|
||||
runtimeExpected = mapOf(
|
||||
userWalletId.stringValue to setOf(
|
||||
MockNetworkStatusFactory.createVerified().toSimple(),
|
||||
|
|
@ -69,6 +71,7 @@ internal class StoreActualNetworkStatusTest(private val model: Model) {
|
|||
),
|
||||
Model(
|
||||
status = MockNetworkStatusFactory.createNoAccount(),
|
||||
isSuccess = true,
|
||||
runtimeExpected = mapOf(
|
||||
userWalletId.stringValue to setOf(
|
||||
MockNetworkStatusFactory.createNoAccount().toSimple(),
|
||||
|
|
@ -82,6 +85,7 @@ internal class StoreActualNetworkStatusTest(private val model: Model) {
|
|||
),
|
||||
Model(
|
||||
status = MockNetworkStatusFactory.createMissedDerivation(),
|
||||
isSuccess = true,
|
||||
runtimeExpected = mapOf(
|
||||
userWalletId.stringValue to setOf(
|
||||
MockNetworkStatusFactory.createMissedDerivation().toSimple(),
|
||||
|
|
@ -91,11 +95,8 @@ internal class StoreActualNetworkStatusTest(private val model: Model) {
|
|||
),
|
||||
Model(
|
||||
status = MockNetworkStatusFactory.createUnreachable(),
|
||||
runtimeExpected = mapOf(
|
||||
userWalletId.stringValue to setOf(
|
||||
MockNetworkStatusFactory.createUnreachable().toSimple(),
|
||||
),
|
||||
),
|
||||
isSuccess = false,
|
||||
runtimeExpected = mapOf(),
|
||||
persistenceExpected = mapOf(),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue