Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package com.simprints.feature.dashboard.logout.usecase

import com.simprints.infra.authlogic.AuthManager
import com.simprints.infra.enrolment.records.repository.local.migration.RealmToRoomMigrationFlagsStore
import com.simprints.infra.sync.SyncOrchestrator
import kotlinx.coroutines.runBlocking
import javax.inject.Inject

internal class LogoutUseCase @Inject constructor(
private val syncOrchestrator: SyncOrchestrator,
private val authManager: AuthManager,
private val flagsStore: RealmToRoomMigrationFlagsStore,
) {
operator fun invoke() = runBlocking {
// Cancel all background sync
syncOrchestrator.cancelBackgroundWork()
syncOrchestrator.deleteEventSyncInfo()
// sign out the user
authManager.signOut()
// Reset migration flags
flagsStore.clearMigrationFlags()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ internal class SyncViewModel @Inject constructor(
_syncToBFSIDAllowed.postValue(configuration.canSyncDataToSimprints() || configuration.isEventDownSyncAllowed())
}
eventSyncManager
.countEventsToUpload(EventType.ENROLMENT_V2)
.countEventsToUpload(listOf(EventType.ENROLMENT_V2, EventType.ENROLMENT_V4))
.collect { upSyncCountLiveData.postValue(it) }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ internal class AboutViewModel @Inject constructor(
}
}

private suspend fun hasEventsToUpload(): Boolean = eventSyncManager.countEventsToUpload(type = null).first() > 0
private suspend fun hasEventsToUpload(): Boolean = eventSyncManager.countEventsToUpload().first() > 0

private suspend fun canSyncDataToSimprints(): Boolean = configManager.getProjectConfiguration().canSyncDataToSimprints()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import com.simprints.infra.sync.SyncOrchestrator
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import javax.inject.Inject

Expand Down Expand Up @@ -123,11 +122,11 @@ internal class SyncInfoViewModel @Inject constructor(
_isReloginRequired.addSource(lastSyncState) { lastSyncStateValue ->
_isReloginRequired.postValue(lastSyncStateValue.isSyncFailedBecauseReloginRequired())
}
viewModelScope.launch { getRecordsToUpSync() }
}

fun refreshInformation() {
_recordsInLocal.postValue(null)
_recordsToUpSync.postValue(null)
_recordsToDownSync.postValue(null)
_imagesToUpload.postValue(null)
_moduleCounts.postValue(listOf())
Expand Down Expand Up @@ -179,7 +178,6 @@ internal class SyncInfoViewModel @Inject constructor(
awaitAll(
async { _configuration.postValue(configManager.getProjectConfiguration()) },
async { _recordsInLocal.postValue(getRecordsInLocal(projectId)) },
async { _recordsToUpSync.postValue(getRecordsToUpSync()) },
async { _recordsToDownSync.postValue(fetchRecordsToCreateAndDeleteCount()) },
async { _imagesToUpload.postValue(imageRepository.getNumberOfImagesToUpload(projectId)) },
async { _moduleCounts.postValue(getModuleCounts(projectId)) },
Expand Down Expand Up @@ -207,10 +205,9 @@ internal class SyncInfoViewModel @Inject constructor(

private suspend fun getRecordsInLocal(projectId: String): Int = enrolmentRecordRepository.count(SubjectQuery(projectId = projectId))

private suspend fun getRecordsToUpSync(): Int = eventSyncManager
.countEventsToUpload(EventType.ENROLMENT_V2)
.firstOrNull()
?: 0
private suspend fun getRecordsToUpSync() = eventSyncManager
.countEventsToUpload(listOf(EventType.ENROLMENT_V2, EventType.ENROLMENT_V4))
.collect { _recordsToUpSync.postValue(it) }

private suspend fun fetchRecordsToCreateAndDeleteCount(): DownSyncCounts =
if (configManager.getProjectConfiguration().isEventDownSyncAllowed()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.simprints.feature.dashboard.logout.usecase

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.simprints.infra.authlogic.AuthManager
import com.simprints.infra.enrolment.records.repository.local.migration.RealmToRoomMigrationFlagsStore
import com.simprints.infra.sync.SyncOrchestrator
import com.simprints.testtools.common.coroutines.TestCoroutineRule
import io.mockk.MockKAnnotations
Expand All @@ -25,6 +26,9 @@ class LogoutUseCaseTest {
@MockK
private lateinit var authManager: AuthManager

@MockK
private lateinit var flagsStore: RealmToRoomMigrationFlagsStore

private lateinit var useCase: LogoutUseCase

@Before
Expand All @@ -34,6 +38,7 @@ class LogoutUseCaseTest {
useCase = LogoutUseCase(
syncOrchestrator = syncOrchestrator,
authManager = authManager,
flagsStore = flagsStore,
)
}

Expand All @@ -45,6 +50,7 @@ class LogoutUseCaseTest {
syncOrchestrator.cancelBackgroundWork()
syncOrchestrator.deleteEventSyncInfo()
authManager.signOut()
flagsStore.clearMigrationFlags()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.simprints.infra.config.store.models.UpSynchronizationConfiguration
import com.simprints.infra.config.store.models.UpSynchronizationConfiguration.SimprintsUpSynchronizationConfiguration
import com.simprints.infra.config.store.models.UpSynchronizationConfiguration.UpSynchronizationKind.ALL
import com.simprints.infra.config.sync.ConfigManager
import com.simprints.infra.events.event.domain.models.EventType
import com.simprints.infra.eventsync.EventSyncManager
import com.simprints.infra.eventsync.status.models.EventSyncState
import com.simprints.infra.eventsync.status.models.EventSyncWorkerState
Expand Down Expand Up @@ -234,7 +235,7 @@ internal class SyncViewModelTest {
@Test
fun `should post a SyncPendingUpload card state if there are records to upload`() {
coEvery { configManager.getDeviceConfiguration() } returns deviceConfiguration
coEvery { eventSyncManager.countEventsToUpload(any()) }.returns(flowOf(2))
coEvery { eventSyncManager.countEventsToUpload(any<List<EventType>>()) }.returns(flowOf(2))

isConnected.value = true
syncState.value = EventSyncState(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,7 @@ class AboutViewModelTest {
true -> 1
false -> 0
}
coEvery { eventSyncManager.countEventsToUpload(any()) } returns flowOf(
countEventsToUpload,
)
coEvery { eventSyncManager.countEventsToUpload() } returns flowOf(countEventsToUpload)
coEvery { configManager.getProjectConfiguration() } returns buildProjectConfigurationMock(
upSyncKind,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,19 +101,21 @@ class SyncInfoViewModelTest {
stateLiveData = MutableLiveData<EventSyncState>()
every { eventSyncManager.getLastSyncState() } returns stateLiveData
coEvery { configManager.getProject(PROJECT_ID) } returns project
viewModel = SyncInfoViewModel(
configManager = configManager,
connectivityTracker = connectivityTracker,
enrolmentRecordRepository = enrolmentRecordRepository,
authStore = authStore,
imageRepository = imageRepository,
eventSyncManager = eventSyncManager,
syncOrchestrator = syncOrchestrator,
tokenizationProcessor = tokenizationProcessor,
recentUserActivityManager = recentUserActivityManager,
)
viewModel = createViewModel()
}

private fun createViewModel() = SyncInfoViewModel(
configManager = configManager,
connectivityTracker = connectivityTracker,
enrolmentRecordRepository = enrolmentRecordRepository,
authStore = authStore,
imageRepository = imageRepository,
eventSyncManager = eventSyncManager,
syncOrchestrator = syncOrchestrator,
tokenizationProcessor = tokenizationProcessor,
recentUserActivityManager = recentUserActivityManager,
)

@Test
fun `should initialize the configuration live data correctly`() = runTest {
val configuration = mockk<ProjectConfiguration>(relaxed = true)
Expand All @@ -138,10 +140,11 @@ class SyncInfoViewModelTest {
fun `should initialize the recordsToUpSync live data correctly`() = runTest {
val number = 10
coEvery {
eventSyncManager.countEventsToUpload(EventType.ENROLMENT_V2)
eventSyncManager.countEventsToUpload(listOf(EventType.ENROLMENT_V2, EventType.ENROLMENT_V4))
} returns flowOf(number)

viewModel.refreshInformation()
// upSync count collected on init, so need to rebuild for mocking to take effect
viewModel = createViewModel()

assertThat(viewModel.recordsToUpSync.getOrAwaitValue()).isEqualTo(number)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.simprints.feature.dashboard.tools.di

import android.content.Context
import androidx.work.WorkManager
import com.simprints.core.AppScope
import com.simprints.core.AvailableProcessors
import com.simprints.core.CoreModule
Expand All @@ -17,6 +19,7 @@ import com.simprints.core.tools.utils.StringTokenizer
import com.simprints.testtools.unit.EncodingUtilsImplForTests
import dagger.Module
import dagger.Provides
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import dagger.hilt.testing.TestInstallIn
import io.mockk.mockk
Expand Down Expand Up @@ -88,4 +91,9 @@ object FakeCoreModule {
@Provides
@Singleton
fun provideEncodingUtils(): EncodingUtils = EncodingUtilsImplForTests

@Provides
fun provideWorkManager(
@ApplicationContext context: Context,
): WorkManager = WorkManager.getInstance(context)
}
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ firebase_perfPlugin_version = "1.4.2"
firebase_distrtibutionPlugin_version = "5.0.0"

# [MS-483] Newer versions of Retrofit (>=2.10.0) don't support android apis <=25 beacuse of the internal Jackson library
retrofit_version = "3.0.0"
retrofit_version = "2.9.0"
okttp_version = "4.12.0"
# Newer versions of Jackson don't support android apis <=25.Jackson shouldn't be updated as long as SID MIN supported APIs <=25
jackson_version = "2.13.4"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.simprints.infra.config.store.models.Project
import com.simprints.infra.config.store.models.ProjectConfiguration
import com.simprints.infra.config.store.models.ProjectWithConfig
import com.simprints.infra.enrolment.records.repository.EnrolmentRecordRepository
import com.simprints.infra.enrolment.records.repository.local.migration.RealmToRoomMigrationScheduler
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onStart
import javax.inject.Inject
Expand All @@ -16,15 +17,17 @@ class ConfigManager @Inject constructor(
private val configRepository: ConfigRepository,
private val enrolmentRecordRepository: EnrolmentRecordRepository,
private val configSyncCache: ConfigSyncCache,
private val realmToRoomMigrationScheduler: RealmToRoomMigrationScheduler,
) {
suspend fun refreshProject(projectId: String): ProjectWithConfig = configRepository.refreshProject(projectId).also {
enrolmentRecordRepository.tokenizeExistingRecords(it.project)
configSyncCache.saveUpdateTime()
realmToRoomMigrationScheduler.scheduleMigrationWorkerIfNeeded()
}

suspend fun getProject(projectId: String): Project = try {
configRepository.getProject()
} catch (e: NoSuchElementException) {
} catch (_: NoSuchElementException) {
refreshProject(projectId).project
}

Expand All @@ -35,7 +38,7 @@ class ConfigManager @Inject constructor(
try {
// Try to refresh it with logged in projectId (if any)
refreshProject(configRepository.getProject().id).configuration
} catch (e: Exception) {
} catch (_: Exception) {
// If not logged in the above will fail. However we still depend on the 'default'
// configuration to create the session when login is attempted. Possibly in other
// places, too.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package com.simprints.infra.config.sync

import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.*
import com.simprints.infra.config.store.ConfigRepository
import com.simprints.infra.config.store.models.DeviceConfiguration
import com.simprints.infra.config.store.models.Project
import com.simprints.infra.config.store.models.ProjectConfiguration
import com.simprints.infra.config.store.models.ProjectWithConfig
import com.simprints.infra.enrolment.records.repository.EnrolmentRecordRepository
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import com.simprints.infra.enrolment.records.repository.local.migration.RealmToRoomMigrationScheduler
import io.mockk.*
import io.mockk.impl.annotations.MockK
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.test.runTest
Expand Down Expand Up @@ -43,6 +41,9 @@ class ConfigManagerTest {
@MockK
private lateinit var deviceConfiguration: DeviceConfiguration

@MockK
private lateinit var realmToRoomMigrationScheduler: RealmToRoomMigrationScheduler

@MockK
private lateinit var project: Project

Expand All @@ -53,6 +54,7 @@ class ConfigManagerTest {
configRepository = configRepository,
enrolmentRecordRepository = enrolmentRecordRepository,
configSyncCache = configSyncCache,
realmToRoomMigrationScheduler = realmToRoomMigrationScheduler,
)
}

Expand All @@ -64,6 +66,7 @@ class ConfigManagerTest {
assertThat(refreshedProject).isEqualTo(projectWithConfig)

coVerify { configSyncCache.saveUpdateTime() }
coVerify { realmToRoomMigrationScheduler.scheduleMigrationWorkerIfNeeded() }
}

@Test
Expand All @@ -74,6 +77,14 @@ class ConfigManagerTest {
assertThat(gottenProject).isEqualTo(project)
}

@Test
fun `getProject should call the refresh method when cannot get from local`() = runTest {
coEvery { configRepository.getProject() } throws NoSuchElementException()

configManager.getProject(PROJECT_ID)
coVerify(exactly = 1) { configRepository.refreshProject(PROJECT_ID) }
}

@Test
fun `getProjectConfiguration should call the correct method`() = runTest {
coEvery { configRepository.getProjectConfiguration() } returns projectConfiguration
Expand All @@ -83,6 +94,16 @@ class ConfigManagerTest {
assertThat(gottenProjectConfiguration).isEqualTo(projectConfiguration)
}

@Test
fun `getProjectConfiguration return default config if not logged in`() = runTest {
every { projectConfiguration.projectId } returns ""
coEvery { configRepository.getProjectConfiguration() } returns projectConfiguration
coEvery { configRepository.refreshProject(any()) } throws Exception()

val gottenProjectConfiguration = configManager.getProjectConfiguration()
assertThat(gottenProjectConfiguration).isEqualTo(projectConfiguration)
}

@Test
fun `refreshProjectConfiguration should call the correct method`() = runTest {
coEvery { configRepository.refreshProject(PROJECT_ID) } returns projectWithConfig
Expand Down Expand Up @@ -120,7 +141,7 @@ class ConfigManagerTest {
configManager.getPrivacyNotice(PROJECT_ID, LANGUAGE)
coVerify(exactly = 1) { configRepository.getPrivacyNotice(PROJECT_ID, LANGUAGE) }
}

@Test
fun `watchProjectConfiguration should emit values from the local data source`() = runTest {
val config1 = projectConfiguration.copy(projectId = "project1")
Expand Down
6 changes: 6 additions & 0 deletions infra/core/src/main/java/com/simprints/core/CoreModule.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.simprints.core

import android.content.Context
import androidx.work.WorkManager
import com.lyft.kronos.AndroidClockFactory
import com.simprints.core.tools.exceptions.AppCoroutineExceptionHandler
import com.simprints.core.tools.extentions.deviceHardwareId
Expand Down Expand Up @@ -134,6 +135,11 @@ object CoreModule {
): CoroutineScope = CoroutineScope(
SupervisorJob() + dispatcherMain + AppCoroutineExceptionHandler(),
)

@Provides
fun provideWorkManager(
@ApplicationContext context: Context,
): WorkManager = WorkManager.getInstance(context)
}

@Qualifier
Expand Down
Loading
Loading