Add helper method for observing a data flow when logged in and someone is subscribed (#392)

This commit is contained in:
David Perez
2023-12-14 14:08:57 -06:00
committed by GitHub
parent c34c3dbd1e
commit ec58f57a65
5 changed files with 126 additions and 50 deletions

View File

@@ -0,0 +1,58 @@
package com.x8bit.bitwarden.data.platform.repository.util
import app.cash.turbine.test
import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
class StateFlowExtensionsTest {
@Suppress("MaxLineLength")
@Test
fun `observeWhenSubscribedAndLoggedIn should observe the given flow depending on the state of the source and user flow`() =
runTest {
val userStateFlow = MutableStateFlow<UserStateJson?>(null)
val observerStateFlow = MutableStateFlow("")
val sourceMutableStateFlow = MutableStateFlow(Unit)
assertEquals(0, observerStateFlow.subscriptionCount.value)
sourceMutableStateFlow
.observeWhenSubscribedAndLoggedIn(
userStateFlow = userStateFlow,
observer = { observerStateFlow },
)
.launchIn(backgroundScope)
observerStateFlow.subscriptionCount.test {
// No subscriber to start
assertEquals(0, awaitItem())
userStateFlow.value = mockk<UserStateJson> {
every { activeUserId } returns "user_id_1234"
}
// Still none, since no one has subscribed to the testMutableStateFlow
expectNoEvents()
val job = sourceMutableStateFlow.launchIn(backgroundScope)
// Now we subscribe to the observer flow since have a active user and a listener
assertEquals(1, awaitItem())
userStateFlow.value = mockk<UserStateJson> {
every { activeUserId } returns "user_id_4321"
}
// The user changed, so we clear the previous observer but then resubscribe
// with the new user ID
assertEquals(0, awaitItem())
assertEquals(1, awaitItem())
job.cancel()
// Job is canceled, we should have no more subscribers
assertEquals(0, awaitItem())
}
}
}

View File

@@ -14,10 +14,11 @@ import com.x8bit.bitwarden.data.auth.datasource.network.model.KdfTypeJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorUserDecryptionOptionsJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.TrustedDeviceUserDecryptionOptionsJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.UserDecryptionOptionsJson
import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager
import com.x8bit.bitwarden.data.platform.repository.model.LocalDataState
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.entity.PasswordHistoryEntity
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.GeneratorDiskSource
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.PasswordHistoryDiskSource
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.entity.PasswordHistoryEntity
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.entity.toPasswordHistoryEntity
import com.x8bit.bitwarden.data.tools.generator.datasource.sdk.GeneratorSdkSource
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPassphraseResult
@@ -27,9 +28,11 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
import io.mockk.clearMocks
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.runs
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertEquals
@@ -41,11 +44,16 @@ import java.time.Instant
class GeneratorRepositoryTest {
private val mutableUserStateFlow = MutableStateFlow<UserStateJson?>(null)
private val generatorSdkSource: GeneratorSdkSource = mockk()
private val generatorDiskSource: GeneratorDiskSource = mockk()
private val authDiskSource: AuthDiskSource = mockk()
private val authDiskSource: AuthDiskSource = mockk {
every { userStateFlow } returns mutableUserStateFlow
}
private val passwordHistoryDiskSource: PasswordHistoryDiskSource = mockk()
private val vaultSdkSource: VaultSdkSource = mockk()
private val dispatcherManager = FakeDispatcherManager()
private val repository = GeneratorRepositoryImpl(
generatorSdkSource = generatorSdkSource,
@@ -53,6 +61,7 @@ class GeneratorRepositoryTest {
authDiskSource = authDiskSource,
passwordHistoryDiskSource = passwordHistoryDiskSource,
vaultSdkSource = vaultSdkSource,
dispatcherManager = dispatcherManager,
)
@BeforeEach
@@ -290,8 +299,6 @@ class GeneratorRepositoryTest {
),
)
coEvery { authDiskSource.userStateFlow } returns flowOf(USER_STATE)
coEvery {
passwordHistoryDiskSource.getPasswordHistoriesForUser(USER_STATE.activeUserId)
} returns flowOf(encryptedPasswordHistoryEntities)
@@ -304,6 +311,7 @@ class GeneratorRepositoryTest {
historyFlow.test {
assertEquals(LocalDataState.Loading, awaitItem())
mutableUserStateFlow.value = USER_STATE
assertEquals(LocalDataState.Loaded(decryptedPasswordHistoryList), awaitItem())
cancelAndIgnoreRemainingEvents()
}