NTP-30344 | Girish Suragani | Test cases for RefreshAndSyncDataUseCase (#14634)
Co-authored-by: abhinav-g_navi <abhinav.g@navi.com> Co-authored-by: venkat-praneeth_navi <venkat.praneeth@navi.com>
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2025 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.moneymanager.postonboard.dashboard.usecase
|
||||
|
||||
import com.navi.common.network.models.RepoResult
|
||||
import com.navi.moneymanager.common.analytics.DataSyncEventTrackerImpl
|
||||
import com.navi.moneymanager.common.dataprovider.data.datastore.DataStoreInfoProvider
|
||||
import com.navi.moneymanager.common.dataprovider.domain.RemoteDataProvider
|
||||
import com.navi.moneymanager.common.datasync.DBSyncExecutor
|
||||
import com.navi.moneymanager.common.datasync.SyncStatus
|
||||
import com.navi.moneymanager.common.datasync.model.DataSyncState
|
||||
import com.navi.moneymanager.common.network.di.RoomDataStoreInfoProvider
|
||||
import com.navi.moneymanager.common.network.model.MMConfigResponse
|
||||
import com.navi.moneymanager.common.utils.Constants.LAST_REFRESH_SUCCESSFUL_TIMESTAMP
|
||||
import com.navi.moneymanager.testsetup.DataSyncHelperTest
|
||||
import io.mockk.MockKAnnotations
|
||||
import io.mockk.Runs
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.impl.annotations.RelaxedMockK
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkObject
|
||||
import io.mockk.unmockkAll
|
||||
import junit.framework.TestCase.assertFalse
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.cancelAndJoin
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.setMain
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class RefreshAndSyncDataUseCaseTest {
|
||||
|
||||
@RelaxedMockK
|
||||
@RoomDataStoreInfoProvider
|
||||
private lateinit var dbDataStoreProvider: DataStoreInfoProvider
|
||||
|
||||
@RelaxedMockK private lateinit var remoteDataProvider: RemoteDataProvider
|
||||
|
||||
@RelaxedMockK private lateinit var dBSyncExecutor: DBSyncExecutor
|
||||
|
||||
private val dataSyncHelperTest = DataSyncHelperTest()
|
||||
|
||||
private val testDispatcher = StandardTestDispatcher()
|
||||
|
||||
private lateinit var refreshAndSyncDataUseCase: RefreshAndSyncDataUseCase
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockKAnnotations.init(this, relaxed = true)
|
||||
Dispatchers.setMain(testDispatcher)
|
||||
mockkObject(DataSyncEventTrackerImpl)
|
||||
refreshAndSyncDataUseCase =
|
||||
RefreshAndSyncDataUseCase(
|
||||
remoteDataProvider = remoteDataProvider,
|
||||
dbDataStoreProvider = dbDataStoreProvider,
|
||||
dBSyncExecutor = dBSyncExecutor,
|
||||
)
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
Dispatchers.resetMain()
|
||||
unmockkAll()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `execute should refresh data and start polling`() = runBlocking {
|
||||
val mockResponse = mockk<MMConfigResponse>(relaxed = true)
|
||||
val refreshDataResponse = dataSyncHelperTest.createRefreshDataResponse()
|
||||
val mockSyncStatusFlow =
|
||||
dataSyncHelperTest.createMockSyncStatusFlow(
|
||||
DataSyncState.Completed,
|
||||
DataSyncState.Completed,
|
||||
)
|
||||
val isRefreshingFlow = refreshAndSyncDataUseCase.isRefreshing
|
||||
val refreshingStates = mutableListOf<Boolean>()
|
||||
|
||||
coEvery { remoteDataProvider.refreshData() } returns refreshDataResponse
|
||||
every { dBSyncExecutor.dataSyncStatus } returns mockSyncStatusFlow
|
||||
every { dBSyncExecutor.initDBSyncExecutor(any()) } just Runs
|
||||
dataSyncHelperTest.mockEventTrackers()
|
||||
|
||||
val job = launch { refreshAndSyncDataUseCase.execute(this, mockResponse) }
|
||||
val job2 = launch { isRefreshingFlow.collect { refreshingStates.add(it) } }
|
||||
|
||||
coVerify { remoteDataProvider.refreshData() }
|
||||
coVerify { dbDataStoreProvider.saveLongData(LAST_REFRESH_SUCCESSFUL_TIMESTAMP, 1000L) }
|
||||
assertFalse(refreshingStates.last())
|
||||
|
||||
job.cancelAndJoin()
|
||||
job2.cancelAndJoin()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `execute should not start polling if response data is null`() = runBlocking {
|
||||
val mockResponse = mockk<MMConfigResponse>(relaxed = true)
|
||||
coEvery { remoteDataProvider.refreshData() } returns RepoResult(null)
|
||||
|
||||
refreshAndSyncDataUseCase.execute(this, mockResponse)
|
||||
|
||||
coVerify { remoteDataProvider.refreshData() }
|
||||
coVerify(exactly = 0) { dbDataStoreProvider.saveLongData(any(), any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `execute should stop polling if account sync fails`() = runBlocking {
|
||||
val mockResponse = dataSyncHelperTest.createMockConfigResponse()
|
||||
val refreshDataResponse = dataSyncHelperTest.createRefreshDataResponse()
|
||||
val mockSyncStatusFlow =
|
||||
dataSyncHelperTest.createMockSyncStatusFlow(
|
||||
DataSyncState.InProgress,
|
||||
DataSyncState.InProgress,
|
||||
)
|
||||
val pollingStatusResponse =
|
||||
dataSyncHelperTest.createPollingStatusResponse(
|
||||
accountDetailsStatus = SyncStatus.FAILED.name
|
||||
)
|
||||
|
||||
coEvery { remoteDataProvider.refreshData() } returns refreshDataResponse
|
||||
coEvery { remoteDataProvider.pollSyncStatus(any()) } returns pollingStatusResponse
|
||||
every { dBSyncExecutor.dataSyncStatus } returns mockSyncStatusFlow
|
||||
every { dBSyncExecutor.initDBSyncExecutor(any()) } just Runs
|
||||
dataSyncHelperTest.mockEventTrackers()
|
||||
|
||||
val job = launch { refreshAndSyncDataUseCase.execute(this, mockResponse) }
|
||||
|
||||
coVerify { DataSyncEventTrackerImpl.pollingStopped() }
|
||||
job.cancelAndJoin()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `execute should stop polling if all transactions are synced`() = runBlocking {
|
||||
val mockResponse = dataSyncHelperTest.createMockConfigResponse()
|
||||
val refreshDataResponse = dataSyncHelperTest.createRefreshDataResponse()
|
||||
val mockSyncStatusFlow =
|
||||
dataSyncHelperTest.createMockSyncStatusFlow(
|
||||
DataSyncState.InProgress,
|
||||
DataSyncState.InProgress,
|
||||
)
|
||||
val pollingStatusResponse =
|
||||
dataSyncHelperTest.createPollingStatusResponse(
|
||||
oldMonthTxnsStatus = SyncStatus.COMPLETED.name,
|
||||
currMonthTxnsStatus = SyncStatus.COMPLETED.name,
|
||||
accountDetailsStatus = SyncStatus.COMPLETED.name,
|
||||
)
|
||||
|
||||
coEvery { remoteDataProvider.refreshData() } returns refreshDataResponse
|
||||
coEvery { remoteDataProvider.pollSyncStatus(any()) } returns pollingStatusResponse
|
||||
every { dBSyncExecutor.dataSyncStatus } returns mockSyncStatusFlow
|
||||
every { dBSyncExecutor.initDBSyncExecutor(any()) } just Runs
|
||||
dataSyncHelperTest.mockEventTrackers()
|
||||
|
||||
val job = launch { refreshAndSyncDataUseCase.execute(this, mockResponse) }
|
||||
|
||||
coVerify { DataSyncEventTrackerImpl.pollingStopped() }
|
||||
job.cancelAndJoin()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `execute should stop polling when all transactions sync failed`() = runBlocking {
|
||||
val mockResponse = dataSyncHelperTest.createMockConfigResponse()
|
||||
val refreshDataResponse = dataSyncHelperTest.createRefreshDataResponse()
|
||||
val mockSyncStatusFlow =
|
||||
dataSyncHelperTest.createMockSyncStatusFlow(
|
||||
DataSyncState.InProgress,
|
||||
DataSyncState.InProgress,
|
||||
)
|
||||
val pollingStatusResponse =
|
||||
dataSyncHelperTest.createPollingStatusResponse(
|
||||
accountDetailsStatus = SyncStatus.COMPLETED.name,
|
||||
oldMonthTxnsStatus = SyncStatus.FAILED.name,
|
||||
currMonthTxnsStatus = SyncStatus.FAILED.name,
|
||||
)
|
||||
|
||||
coEvery { remoteDataProvider.refreshData() } returns refreshDataResponse
|
||||
coEvery { remoteDataProvider.pollSyncStatus(any()) } returns pollingStatusResponse
|
||||
every { dBSyncExecutor.dataSyncStatus } returns mockSyncStatusFlow
|
||||
every { dBSyncExecutor.initDBSyncExecutor(any()) } just Runs
|
||||
dataSyncHelperTest.mockEventTrackers()
|
||||
|
||||
val job = launch { refreshAndSyncDataUseCase.execute(this, mockResponse) }
|
||||
|
||||
coVerify { DataSyncEventTrackerImpl.pollingStopped() }
|
||||
job.cancelAndJoin()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `execute should stop polling when current month sync failed but all months sync completed`() =
|
||||
runBlocking {
|
||||
val mockResponse = dataSyncHelperTest.createMockConfigResponse()
|
||||
val refreshDataResponse = dataSyncHelperTest.createRefreshDataResponse()
|
||||
val mockSyncStatusFlow =
|
||||
dataSyncHelperTest.createMockSyncStatusFlow(
|
||||
DataSyncState.InProgress,
|
||||
DataSyncState.InProgress,
|
||||
)
|
||||
val pollingStatusResponse =
|
||||
dataSyncHelperTest.createPollingStatusResponse(
|
||||
accountDetailsStatus = SyncStatus.COMPLETED.name,
|
||||
oldMonthTxnsStatus = SyncStatus.COMPLETED.name,
|
||||
currMonthTxnsStatus = SyncStatus.FAILED.name,
|
||||
)
|
||||
|
||||
coEvery { remoteDataProvider.refreshData() } returns refreshDataResponse
|
||||
coEvery { remoteDataProvider.pollSyncStatus(any()) } returns pollingStatusResponse
|
||||
every { dBSyncExecutor.dataSyncStatus } returns mockSyncStatusFlow
|
||||
every { dBSyncExecutor.initDBSyncExecutor(any()) } just Runs
|
||||
dataSyncHelperTest.mockEventTrackers()
|
||||
|
||||
val job = launch { refreshAndSyncDataUseCase.execute(this, mockResponse) }
|
||||
|
||||
coVerify { DataSyncEventTrackerImpl.pollingStopped() }
|
||||
job.cancelAndJoin()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2025 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.moneymanager.testsetup
|
||||
|
||||
import com.navi.common.network.models.RepoResult
|
||||
import com.navi.moneymanager.common.analytics.DataSyncEventTrackerImpl
|
||||
import com.navi.moneymanager.common.datasync.model.DataSyncState
|
||||
import com.navi.moneymanager.common.datasync.model.DataSyncStatus
|
||||
import com.navi.moneymanager.common.network.model.MMConfigResponse
|
||||
import com.navi.moneymanager.common.network.model.PollingConfig
|
||||
import com.navi.moneymanager.common.network.model.PollingStatusResponse
|
||||
import com.navi.moneymanager.common.network.model.RefreshDataResponse
|
||||
import io.mockk.Runs
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class DataSyncHelperTest @Inject constructor() {
|
||||
|
||||
fun createRefreshDataResponse(): RepoResult<RefreshDataResponse> {
|
||||
return RepoResult(
|
||||
data =
|
||||
RefreshDataResponse(
|
||||
requestId = "testRequestId",
|
||||
lastRefreshSuccessTimestamp = 1000L,
|
||||
isAARefreshApplicable = true,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun createMockSyncStatusFlow(
|
||||
allMonthsStatus: DataSyncState,
|
||||
currentMonthStatus: DataSyncState,
|
||||
): MutableStateFlow<DataSyncStatus> {
|
||||
return MutableStateFlow(
|
||||
DataSyncStatus(
|
||||
allMonthsSyncStatus = allMonthsStatus,
|
||||
currentMonthSyncStatus = currentMonthStatus,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun createMockConfigResponse(): MMConfigResponse {
|
||||
return MMConfigResponse(dataSyncPollingConfig = PollingConfig(10, 0, 5))
|
||||
}
|
||||
|
||||
fun createPollingStatusResponse(
|
||||
oldMonthTxnsStatus: String? = null,
|
||||
currMonthTxnsStatus: String? = null,
|
||||
accountDetailsStatus: String? = null,
|
||||
): RepoResult<PollingStatusResponse> {
|
||||
return RepoResult(
|
||||
data =
|
||||
PollingStatusResponse(
|
||||
oldMonthTxnsStatus = oldMonthTxnsStatus,
|
||||
currMonthTxnsStatus = currMonthTxnsStatus,
|
||||
accountDetailsStatus = accountDetailsStatus,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun mockEventTrackers() {
|
||||
every {
|
||||
DataSyncEventTrackerImpl.refreshStarted(any(), any())
|
||||
DataSyncEventTrackerImpl.periodicTaskSchedulerCreated()
|
||||
DataSyncEventTrackerImpl.pollingStarted()
|
||||
DataSyncEventTrackerImpl.pollingTimeout()
|
||||
DataSyncEventTrackerImpl.pollingStopped()
|
||||
} just Runs
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user