PM-10894: Add flag for disabling remote feature flag configuration (#3729)
Some checks failed
Crowdin Push / Crowdin Push (push) Waiting to run
Scan / Check PR run (push) Failing after 0s
Scan / SAST scan (push) Has been skipped
Scan / Quality scan (push) Has been skipped
Test / Check PR run (push) Failing after 0s
Test / Test (push) Has been skipped

This commit is contained in:
David Perez 2024-08-14 14:06:09 -05:00 committed by GitHub
parent 8a4d436f1f
commit 63884e8518
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 62 additions and 20 deletions

View file

@ -42,7 +42,9 @@ class FeatureFlagManagerImpl(
private fun <T : Any> ServerConfig?.getFlagValueOrDefault(key: FlagKey<T>): T {
val defaultValue = key.defaultValue
return this?.serverData
if (!key.isRemotelyConfigured) return key.defaultValue
return this
?.serverData
?.featureStates
?.get(key.keyName)
?.let {

View file

@ -2,50 +2,75 @@ package com.x8bit.bitwarden.data.platform.manager.model
/**
* Class to hold feature flag keys.
* @property [keyName] corresponds to the string value of a given key
* @property [defaultValue] corresponds to default value of the flag of type [T]
*/
sealed class FlagKey<out T : Any> {
/**
* The string value of the given key. This must match the network value.
*/
abstract val keyName: String
/**
* The value to be used if the flags value cannot be determined or is not remotely configured.
*/
abstract val defaultValue: T
/**
* Data object holding the key for Email Verification feature
* Indicates if the flag should respect the network value or not.
*/
abstract val isRemotelyConfigured: Boolean
/**
* Data object holding the key for Email Verification feature.
*/
data object EmailVerification : FlagKey<Boolean>() {
override val keyName: String = "email-verification"
override val defaultValue: Boolean = false
override val isRemotelyConfigured: Boolean = false
}
/**
* Data object holding the feature flag key for the Onboarding Carousel feature
* Data object holding the feature flag key for the Onboarding Carousel feature.
*/
data object OnboardingCarousel : FlagKey<Boolean>() {
override val keyName: String = "native-carousel-flow"
override val defaultValue: Boolean = false
override val isRemotelyConfigured: Boolean = false
}
/**
* Data object holding the feature flag key for the new onboarding feature
* Data object holding the feature flag key for the new onboarding feature.
*/
data object OnboardingFlow : FlagKey<Boolean>() {
override val keyName: String = "native-create-account-flow"
override val defaultValue: Boolean = false
override val isRemotelyConfigured: Boolean = false
}
/**
* Data object holding the key for an Int flag to be used in tests
* Data object holding the key for a [Boolean] flag to be used in tests.
*/
data object DummyInt : FlagKey<Int>() {
data object DummyBoolean : FlagKey<Boolean>() {
override val keyName: String = "dummy-boolean"
override val defaultValue: Boolean = false
override val isRemotelyConfigured: Boolean = true
}
/**
* Data object holding the key for an [Int] flag to be used in tests.
*/
data class DummyInt(
override val isRemotelyConfigured: Boolean = true,
) : FlagKey<Int>() {
override val keyName: String = "dummy-int"
override val defaultValue: Int = Int.MIN_VALUE
}
/**
* Data object holding the key for an String flag to be used in tests
* Data object holding the key for a [String] flag to be used in tests.
*/
data object DummyString : FlagKey<String>() {
override val keyName: String = "dummy-string"
override val defaultValue: String = "defaultValue"
override val isRemotelyConfigured: Boolean = true
}
}

View file

@ -43,7 +43,7 @@ class FeatureFlagManagerTest {
// This should trigger a new server config to be fetched
fakeServerConfigRepository.serverConfigValue = SERVER_CONFIG
manager.getFeatureFlagFlow(FlagKey.EmailVerification).test {
manager.getFeatureFlagFlow(FlagKey.DummyBoolean).test {
assertNotNull(
awaitItem(),
)
@ -55,7 +55,7 @@ class FeatureFlagManagerTest {
runTest {
fakeServerConfigRepository.serverConfigValue = null
manager.getFeatureFlagFlow(FlagKey.EmailVerification).test {
manager.getFeatureFlagFlow(FlagKey.DummyBoolean).test {
assertFalse(
awaitItem(),
)
@ -65,7 +65,7 @@ class FeatureFlagManagerTest {
@Test
fun `getFeatureFlag Boolean should return value if exists`() = runTest {
val flagValue = manager.getFeatureFlag(
key = FlagKey.EmailVerification,
key = FlagKey.DummyBoolean,
forceRefresh = true,
)
assertTrue(flagValue)
@ -99,7 +99,7 @@ class FeatureFlagManagerTest {
)
val flagValue = manager.getFeatureFlag(
key = FlagKey.DummyInt,
key = FlagKey.DummyInt(),
forceRefresh = false,
)
@ -120,7 +120,7 @@ class FeatureFlagManagerTest {
)
val flagValue = manager.getFeatureFlag(
key = FlagKey.DummyInt,
key = FlagKey.DummyInt(),
forceRefresh = false,
)
@ -192,7 +192,22 @@ class FeatureFlagManagerTest {
fakeServerConfigRepository.serverConfigValue = null
val flagValue = manager.getFeatureFlag(
key = FlagKey.DummyInt,
key = FlagKey.DummyInt(),
forceRefresh = false,
)
assertEquals(
Int.MIN_VALUE,
flagValue,
)
}
@Test
fun `getFeatureFlag Int should return default value when not remotely controlled`() = runTest {
fakeServerConfigRepository.serverConfigValue = null
val flagValue = manager.getFeatureFlag(
key = FlagKey.DummyInt(isRemotelyConfigured = false),
forceRefresh = false,
)
@ -225,7 +240,7 @@ class FeatureFlagManagerTest {
),
)
val flagValue = manager.getFeatureFlag(key = FlagKey.DummyInt)
val flagValue = manager.getFeatureFlag(key = FlagKey.DummyInt())
assertEquals(Int.MIN_VALUE, flagValue)
}
@ -273,7 +288,7 @@ private val SERVER_CONFIG = ServerConfig(
ssoUrl = "http://localhost:51822",
),
featureStates = mapOf(
"email-verification" to JsonPrimitive(true),
"dummy-boolean" to JsonPrimitive(true),
"flexible-collections-v-1" to JsonPrimitive(false),
),
),

View file

@ -14,8 +14,8 @@ class FakeServerConfigRepository : ServerConfigRepository {
var serverConfigValue: ServerConfig?
get() = mutableServerConfigFlow.value
set(value) {
mutableServerConfigFlow.value = value
}
mutableServerConfigFlow.value = value
}
private val mutableServerConfigFlow = MutableStateFlow<ServerConfig?>(SERVER_CONFIG)
@ -52,7 +52,7 @@ private val SERVER_CONFIG = ServerConfig(
featureStates = mapOf(
"duo-redirect" to JsonPrimitive(true),
"flexible-collections-v-1" to JsonPrimitive(false),
"email-verification" to JsonPrimitive(true),
"dummy-boolean" to JsonPrimitive(true),
),
),
)