BIT-752: Add Environment/EnvironmentRepository/EnvironmentDiskSource (#151)

This commit is contained in:
Brian Yencho
2023-10-24 10:46:33 -05:00
committed by GitHub
parent 6b62cc7b7a
commit 689cc2be27
15 changed files with 575 additions and 24 deletions

View File

@@ -0,0 +1,86 @@
package com.x8bit.bitwarden.data.platform.datasource.disk
import app.cash.turbine.test
import com.x8bit.bitwarden.data.auth.datasource.disk.model.EnvironmentUrlDataJson
import com.x8bit.bitwarden.data.platform.base.FakeSharedPreferences
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Test
class EnvironmentDiskSourceTest {
private val fakeSharedPreferences = FakeSharedPreferences()
@OptIn(ExperimentalSerializationApi::class)
private val json = Json {
ignoreUnknownKeys = true
explicitNulls = false
}
private val environmentDiskSource = EnvironmentDiskSourceImpl(
sharedPreferences = fakeSharedPreferences,
json = json,
)
@Test
fun `preAuthEnvironmentUrlData should pull from and update SharedPreferences`() {
val environmentKey = "bwPreferencesStorage:preAuthEnvironmentUrls"
// Shared preferences and the repository start with the same value.
assertNull(environmentDiskSource.preAuthEnvironmentUrlData)
assertNull(fakeSharedPreferences.getString(environmentKey, null))
// Updating the repository updates shared preferences
environmentDiskSource.preAuthEnvironmentUrlData = ENVIRONMENT_URL_DATA
assertEquals(
json.parseToJsonElement(
ENVIRONMENT_URL_DATA_JSON,
),
json.parseToJsonElement(
fakeSharedPreferences.getString(environmentKey, null)!!,
),
)
// Update SharedPreferences updates the repository
fakeSharedPreferences.edit().putString(environmentKey, null).apply()
assertNull(environmentDiskSource.preAuthEnvironmentUrlData)
}
@Test
fun `preAuthEnvironmentUrlDataFlow should react to changes in preAuthEnvironmentUrlData`() =
runTest {
environmentDiskSource.preAuthEnvironmentUrlDataFlow.test {
// The initial values of the Flow and the property are in sync
assertNull(environmentDiskSource.preAuthEnvironmentUrlData)
assertNull(awaitItem())
// Updating the repository updates shared preferences
environmentDiskSource.preAuthEnvironmentUrlData = ENVIRONMENT_URL_DATA
assertEquals(ENVIRONMENT_URL_DATA, awaitItem())
}
}
}
private const val ENVIRONMENT_URL_DATA_JSON = """
{
"base": "base",
"api": "api",
"identity": "identity",
"icon": "icon",
"notifications": "notifications",
"webVault": "webVault",
"events": "events"
}
"""
private val ENVIRONMENT_URL_DATA = EnvironmentUrlDataJson(
base = "base",
api = "api",
identity = "identity",
icon = "icon",
notifications = "notifications",
webVault = "webVault",
events = "events",
)

View File

@@ -0,0 +1,123 @@
package com.x8bit.bitwarden.data.platform.repository
import app.cash.turbine.test
import com.x8bit.bitwarden.data.auth.datasource.disk.model.EnvironmentUrlDataJson
import com.x8bit.bitwarden.data.platform.datasource.disk.EnvironmentDiskSource
import com.x8bit.bitwarden.data.platform.repository.model.Environment
import com.x8bit.bitwarden.data.platform.repository.util.toEnvironmentUrls
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.unmockkStatic
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.onSubscription
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
class EnvironmentRepositoryTest {
private val fakeEnvironmentDiskSource = FakeEnvironmentDiskSource()
@OptIn(ExperimentalCoroutinesApi::class)
private val repository = EnvironmentRepositoryImpl(
environmentDiskSource = fakeEnvironmentDiskSource,
dispatcher = UnconfinedTestDispatcher(),
)
@BeforeEach
fun setUp() {
mockkStatic(ENVIRONMENT_EXTENSIONS_PATH)
}
@AfterEach
fun tearDown() {
unmockkStatic(ENVIRONMENT_EXTENSIONS_PATH)
}
@Test
fun `environment should pull from and update EnvironmentDiskSource`() {
val environmentUrlDataJson = mockk<EnvironmentUrlDataJson>()
val environment = mockk<Environment>() {
every { environmentUrlData } returns environmentUrlDataJson
}
every { environmentUrlDataJson.toEnvironmentUrls() } returns environment
// The repository exposes a non-null default value when the disk source is empty
assertNull(fakeEnvironmentDiskSource.preAuthEnvironmentUrlData)
assertEquals(
Environment.Us,
repository.environment,
)
// Updating the repository updates the disk source
repository.environment = environment
assertEquals(
environmentUrlDataJson,
fakeEnvironmentDiskSource.preAuthEnvironmentUrlData,
)
// Updating the disk source updates the repository
fakeEnvironmentDiskSource.preAuthEnvironmentUrlData = null
assertEquals(
Environment.Us,
repository.environment,
)
fakeEnvironmentDiskSource.preAuthEnvironmentUrlData = environmentUrlDataJson
assertEquals(
environment,
repository.environment,
)
}
@Test
fun `environmentStateFow should react to changes in environment`() = runTest {
val environmentUrlDataJson = mockk<EnvironmentUrlDataJson>()
val environment = mockk<Environment>() {
every { environmentUrlData } returns environmentUrlDataJson
}
every { environmentUrlDataJson.toEnvironmentUrls() } returns environment
repository.environmentStateFlow.test {
// The initial values of the Flow and the property are in sync
assertEquals(
Environment.Us,
repository.environment,
)
assertEquals(
Environment.Us,
awaitItem(),
)
// Updating the property causes a flow emissions
repository.environment = environment
assertEquals(environment, awaitItem())
}
}
}
private const val ENVIRONMENT_EXTENSIONS_PATH =
"com.x8bit.bitwarden.data.platform.repository.util.EnvironmentExtensionsKt"
private class FakeEnvironmentDiskSource : EnvironmentDiskSource {
override var preAuthEnvironmentUrlData: EnvironmentUrlDataJson? = null
set(value) {
field = value
mutablePreAuthEnvironmentUrlDataFlow.tryEmit(value)
}
override val preAuthEnvironmentUrlDataFlow: Flow<EnvironmentUrlDataJson?>
get() = mutablePreAuthEnvironmentUrlDataFlow
.onSubscription { emit(preAuthEnvironmentUrlData) }
private val mutablePreAuthEnvironmentUrlDataFlow =
MutableSharedFlow<EnvironmentUrlDataJson?>(
replay = 1,
extraBufferCapacity = Int.MAX_VALUE,
)
}

View File

@@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.platform.repository
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.auth.repository.model.AuthState
import com.x8bit.bitwarden.data.platform.datasource.network.interceptor.AuthTokenInterceptor
import com.x8bit.bitwarden.data.platform.repository.model.Environment
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -16,11 +17,16 @@ import org.junit.jupiter.api.Test
@OptIn(ExperimentalCoroutinesApi::class)
class NetworkConfigRepositoryTest {
private val mutableAuthStateFlow = MutableStateFlow<AuthState>(AuthState.Uninitialized)
private val mutableEnvironmentStateFlow = MutableStateFlow<Environment>(Environment.Us)
private val authRepository: AuthRepository = mockk() {
every { authStateFlow } returns mutableAuthStateFlow
}
private val environmentRepository: EnvironmentRepository = mockk {
every { environmentStateFlow } returns mutableEnvironmentStateFlow
}
private val authTokenInterceptor = AuthTokenInterceptor()
private lateinit var networkConfigRepository: NetworkConfigRepository
@@ -30,6 +36,7 @@ class NetworkConfigRepositoryTest {
networkConfigRepository = NetworkConfigRepositoryImpl(
authRepository = authRepository,
authTokenInterceptor = authTokenInterceptor,
environmentRepository = environmentRepository,
dispatcher = UnconfinedTestDispatcher(),
)
}

View File

@@ -0,0 +1,43 @@
package com.x8bit.bitwarden.data.platform.repository.util
import com.x8bit.bitwarden.data.auth.datasource.disk.model.EnvironmentUrlDataJson
import com.x8bit.bitwarden.data.platform.repository.model.Environment
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
class EnvironmentExtensionsTest {
@Test
fun `toEnvironmentUrls should correctly convert US urls to the expected type`() {
assertEquals(
Environment.Us,
EnvironmentUrlDataJson.DEFAULT_US.toEnvironmentUrls(),
)
}
@Test
fun `toEnvironmentUrls should correctly convert EU urls to the expected type`() {
assertEquals(
Environment.Eu,
EnvironmentUrlDataJson.DEFAULT_EU.toEnvironmentUrls(),
)
}
@Test
fun `toEnvironmentUrls should correctly convert custom urls to the expected type`() {
val environmentUrlData = EnvironmentUrlDataJson(
base = "base",
api = "api",
identity = "identity",
icon = "icon",
notifications = "notifications",
webVault = "webVault",
events = "events",
)
assertEquals(
Environment.SelfHosted(
environmentUrlData = environmentUrlData,
),
environmentUrlData.toEnvironmentUrls(),
)
}
}