Add test on api getAvailableFeatures.

This commit is contained in:
Benoit Marty 2025-10-17 12:27:23 +02:00 committed by Benoit Marty
parent 4b76ddaddc
commit ba52b9ad3a
4 changed files with 114 additions and 7 deletions

View file

@ -31,4 +31,5 @@ dependencies {
testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.featureflag.test)
}

View file

@ -14,7 +14,6 @@ import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.featureflag.api.Feature
import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
@ -24,6 +23,7 @@ import kotlinx.coroutines.flow.flowOf
class DefaultFeatureFlagService(
private val providers: Set<@JvmSuppressWildcards FeatureFlagProvider>,
private val buildMeta: BuildMeta,
private val featuresProvider: FeaturesProvider,
) : FeatureFlagService {
override fun isFeatureEnabledFlow(feature: Feature): Flow<Boolean> {
return providers.filter { it.hasFeature(feature) }
@ -44,7 +44,7 @@ class DefaultFeatureFlagService(
includeFinishFeatures: Boolean,
isInLabs: Boolean,
): List<Feature> {
return FeatureFlags.entries.filter { flag ->
return featuresProvider.provide().filter { flag ->
(includeFinishFeatures || !flag.isFinished) &&
flag.isInLabs == isInLabs
}

View file

@ -0,0 +1,24 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.featureflag.impl
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import io.element.android.libraries.featureflag.api.Feature
import io.element.android.libraries.featureflag.api.FeatureFlags
fun interface FeaturesProvider {
fun provide(): List<Feature>
}
@ContributesBinding(AppScope::class)
@Inject
class DefaultFeaturesProvider : FeaturesProvider {
override fun provide(): List<Feature> = FeatureFlags.entries
}

View file

@ -9,7 +9,10 @@ package io.element.android.libraries.featureflag.impl
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.featureflag.api.Feature
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeature
import io.element.android.libraries.matrix.test.core.aBuildMeta
import kotlinx.coroutines.test.runTest
import org.junit.Test
@ -18,7 +21,7 @@ class DefaultFeatureFlagServiceTest {
@Test
fun `given service without provider when feature is checked then it returns the default value`() = runTest {
val buildMeta = aBuildMeta()
val featureFlagService = DefaultFeatureFlagService(emptySet(), buildMeta)
val featureFlagService = createDefaultFeatureFlagService(buildMeta = buildMeta)
featureFlagService.isFeatureEnabledFlow(FeatureFlags.Space).test {
assertThat(awaitItem()).isEqualTo(FeatureFlags.Space.defaultValue(buildMeta))
cancelAndIgnoreRemainingEvents()
@ -27,7 +30,7 @@ class DefaultFeatureFlagServiceTest {
@Test
fun `given service without provider when set enabled feature is called then it returns false`() = runTest {
val featureFlagService = DefaultFeatureFlagService(emptySet(), aBuildMeta())
val featureFlagService = createDefaultFeatureFlagService()
val result = featureFlagService.setFeatureEnabled(FeatureFlags.Space, true)
assertThat(result).isFalse()
}
@ -36,7 +39,10 @@ class DefaultFeatureFlagServiceTest {
fun `given service with a runtime provider when set enabled feature is called then it returns true`() = runTest {
val buildMeta = aBuildMeta()
val featureFlagProvider = FakeMutableFeatureFlagProvider(0, buildMeta)
val featureFlagService = DefaultFeatureFlagService(setOf(featureFlagProvider), buildMeta)
val featureFlagService = createDefaultFeatureFlagService(
providers = setOf(featureFlagProvider),
buildMeta = buildMeta,
)
val result = featureFlagService.setFeatureEnabled(FeatureFlags.Space, true)
assertThat(result).isTrue()
}
@ -45,7 +51,10 @@ class DefaultFeatureFlagServiceTest {
fun `given service with a runtime provider and feature enabled when feature is checked then it returns the correct value`() = runTest {
val buildMeta = aBuildMeta()
val featureFlagProvider = FakeMutableFeatureFlagProvider(0, buildMeta)
val featureFlagService = DefaultFeatureFlagService(setOf(featureFlagProvider), buildMeta)
val featureFlagService = createDefaultFeatureFlagService(
providers = setOf(featureFlagProvider),
buildMeta = buildMeta
)
featureFlagService.setFeatureEnabled(FeatureFlags.Space, true)
featureFlagService.isFeatureEnabledFlow(FeatureFlags.Space).test {
assertThat(awaitItem()).isTrue()
@ -59,11 +68,84 @@ class DefaultFeatureFlagServiceTest {
val buildMeta = aBuildMeta()
val lowPriorityFeatureFlagProvider = FakeMutableFeatureFlagProvider(LOW_PRIORITY, buildMeta)
val highPriorityFeatureFlagProvider = FakeMutableFeatureFlagProvider(HIGH_PRIORITY, buildMeta)
val featureFlagService = DefaultFeatureFlagService(setOf(lowPriorityFeatureFlagProvider, highPriorityFeatureFlagProvider), buildMeta)
val featureFlagService = createDefaultFeatureFlagService(
providers = setOf(lowPriorityFeatureFlagProvider, highPriorityFeatureFlagProvider),
buildMeta = buildMeta
)
lowPriorityFeatureFlagProvider.setFeatureEnabled(FeatureFlags.Space, false)
highPriorityFeatureFlagProvider.setFeatureEnabled(FeatureFlags.Space, true)
featureFlagService.isFeatureEnabledFlow(FeatureFlags.Space).test {
assertThat(awaitItem()).isTrue()
}
}
@Test
fun `getAvailableFeatures should return expected features`() {
val aFinishedLabFeature = FakeFeature(
key = "finished_lab_feature",
title = "Finished Lab Feature",
isFinished = true,
isInLabs = true,
)
val aFinishedDevFeature = FakeFeature(
key = "finished_dev_feature",
title = "Finished Dev Feature",
isFinished = true,
isInLabs = false,
)
val anUnfinishedLabFeature = FakeFeature(
key = "unfinished_lab_feature",
title = "Unfinished Lab Feature",
isFinished = false,
isInLabs = true,
)
val anUnfinishedDevFeature = FakeFeature(
key = "unfinished_dev_feature",
title = "Unfinished Dev Feature",
isFinished = false,
isInLabs = false,
)
val featureFlagService = createDefaultFeatureFlagService(
features = listOf(
aFinishedLabFeature,
aFinishedDevFeature,
anUnfinishedLabFeature,
anUnfinishedDevFeature,
),
)
assertThat(
featureFlagService.getAvailableFeatures(
includeFinishFeatures = false,
isInLabs = true,
)
).containsExactly(anUnfinishedLabFeature)
assertThat(
featureFlagService.getAvailableFeatures(
includeFinishFeatures = true,
isInLabs = true,
)
).containsExactly(aFinishedLabFeature, anUnfinishedLabFeature)
assertThat(
featureFlagService.getAvailableFeatures(
includeFinishFeatures = false,
isInLabs = false,
)
).containsExactly(anUnfinishedDevFeature)
assertThat(
featureFlagService.getAvailableFeatures(
includeFinishFeatures = true,
isInLabs = false,
)
).containsExactly(aFinishedDevFeature, anUnfinishedDevFeature)
}
}
private fun createDefaultFeatureFlagService(
providers: Set<FeatureFlagProvider> = emptySet(),
buildMeta: BuildMeta = aBuildMeta(),
features: List<Feature> = FeatureFlags.entries,
) = DefaultFeatureFlagService(
providers = providers,
buildMeta = buildMeta,
featuresProvider = { features }
)