Browse Source

[FeatureFlag] add more tests

test/jme/compound-poc
ganfra 1 year ago
parent
commit
991c7ff7f0
  1. 1
      features/preferences/impl/build.gradle.kts
  2. 7
      features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt
  3. 80
      features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt
  4. 6
      features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt
  5. 1
      libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlagService.kt
  6. 19
      libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/di/FeatureFlagModule.kt
  7. 27
      libraries/featureflag/test/build.gradle.kts
  8. 36
      libraries/featureflag/test/src/main/java/io/element/android/libraries/featureflag/test/FakeFeatureFlagService.kt
  9. 2
      settings.gradle.kts

1
features/preferences/impl/build.gradle.kts

@ -57,6 +57,7 @@ dependencies { @@ -57,6 +57,7 @@ dependencies {
testImplementation(libs.test.truth)
testImplementation(libs.test.turbine)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.features.rageshake.test)
testImplementation(projects.features.rageshake.impl)
testImplementation(projects.features.logout.impl)

7
features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt

@ -21,24 +21,25 @@ import io.element.android.features.logout.api.LogoutPreferencePresenter @@ -21,24 +21,25 @@ import io.element.android.features.logout.api.LogoutPreferencePresenter
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesPresenter
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
import javax.inject.Inject
class PreferencesRootPresenter @Inject constructor(
private val logoutPresenter: LogoutPreferencePresenter,
private val rageshakePresenter: RageshakePreferencesPresenter,
private val buildMeta: BuildMeta,
private val buildType: BuildType,
) : Presenter<PreferencesRootState> {
@Composable
override fun present(): PreferencesRootState {
val logoutState = logoutPresenter.present()
val rageshakeState = rageshakePresenter.present()
val showDeveloperSettings = buildType != BuildType.RELEASE
return PreferencesRootState(
logoutState = logoutState,
rageshakeState = rageshakeState,
myUser = Async.Uninitialized,
showDeveloperSettings = buildMeta.isDebug
showDeveloperSettings = showDeveloperSettings
)
}
}

80
features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt

@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:OptIn(ExperimentalCoroutinesApi::class)
package io.element.android.features.preferences.impl.developer
import app.cash.molecule.RecompositionClock
import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
class DeveloperSettingsPresenterTest {
@Test
fun `present - ensures initial state is correct`() = runTest {
val presenter = DeveloperSettingsPresenter(
FakeFeatureFlagService()
)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
assertThat(initialState.features).isEmpty()
cancelAndIgnoreRemainingEvents()
}
}
@Test
fun `present - ensures feature list is loaded`() = runTest {
val presenter = DeveloperSettingsPresenter(
FakeFeatureFlagService()
)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
skipItems(1)
val state = awaitItem()
assertThat(state.features).hasSize(FeatureFlags.values().size)
cancelAndIgnoreRemainingEvents()
}
}
@Test
fun `present - ensures state is updated when enabled feature event is triggered`() = runTest {
val presenter = DeveloperSettingsPresenter(
FakeFeatureFlagService()
)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
skipItems(1)
val stateBeforeEvent = awaitItem()
val featureBeforeEvent = stateBeforeEvent.features.first()
stateBeforeEvent.eventSink(DeveloperSettingsEvents.UpdateEnabledFeature(featureBeforeEvent, !featureBeforeEvent.isEnabled))
val stateAfterEvent = awaitItem()
val featureAfterEvent = stateAfterEvent.features.first()
assertThat(featureBeforeEvent.key).isEqualTo(featureAfterEvent.key)
assertThat(featureBeforeEvent.isEnabled).isNotEqualTo(featureAfterEvent.isEnabled)
cancelAndIgnoreRemainingEvents()
}
}
}

6
features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt

@ -27,6 +27,7 @@ import io.element.android.features.rageshake.impl.preferences.DefaultRageshakePr @@ -27,6 +27,7 @@ import io.element.android.features.rageshake.impl.preferences.DefaultRageshakePr
import io.element.android.features.rageshake.test.rageshake.FakeRageShake
import io.element.android.features.rageshake.test.rageshake.FakeRageshakeDataStore
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.matrix.test.FakeMatrixClient
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
@ -38,7 +39,9 @@ class PreferencesRootPresenterTest { @@ -38,7 +39,9 @@ class PreferencesRootPresenterTest {
val logoutPresenter = DefaultLogoutPreferencePresenter(FakeMatrixClient())
val rageshakePresenter = DefaultRageshakePreferencesPresenter(FakeRageShake(), FakeRageshakeDataStore())
val presenter = PreferencesRootPresenter(
logoutPresenter, rageshakePresenter
logoutPresenter,
rageshakePresenter,
BuildType.DEBUG
)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
@ -50,6 +53,7 @@ class PreferencesRootPresenterTest { @@ -50,6 +53,7 @@ class PreferencesRootPresenterTest {
assertThat(initialState.rageshakeState.isSupported).isTrue()
assertThat(initialState.rageshakeState.sensitivity).isEqualTo(1.0f)
assertThat(initialState.myUser).isEqualTo(Async.Uninitialized)
assertThat(initialState.showDeveloperSettings).isEqualTo(true)
}
}
}

1
libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlagService.kt

@ -17,7 +17,6 @@ @@ -17,7 +17,6 @@
package io.element.android.libraries.featureflag.api
interface FeatureFlagService {
/**
* @param feature the feature to check for
*

19
libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/di/FeatureFlagModule.kt

@ -20,36 +20,29 @@ import com.squareup.anvil.annotations.ContributesTo @@ -20,36 +20,29 @@ import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import dagger.multibindings.ElementsIntoSet
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.featureflag.impl.BuildtimeFeatureFlagProvider
import io.element.android.libraries.featureflag.impl.FeatureFlagProvider
import io.element.android.libraries.featureflag.impl.PreferencesFeatureFlagProvider
import io.element.android.libraries.featureflag.impl.RuntimeFeatureFlagProvider
@Module
@ContributesTo(AppScope::class)
object FeatureFlagModule {
@Provides
fun providesRuntimeFeatureFlagProvider(preferencesFeatureFlagProvider: PreferencesFeatureFlagProvider): RuntimeFeatureFlagProvider {
return preferencesFeatureFlagProvider
}
@JvmStatic
@Provides
@ElementsIntoSet
fun providesFeatureFlagProvider(
buildMeta: BuildMeta,
buildType: BuildType,
runtimeFeatureFlagProvider: PreferencesFeatureFlagProvider,
buildtimeFeatureFlagProvider: BuildtimeFeatureFlagProvider,
runtimeFeatureFlagProvider: RuntimeFeatureFlagProvider,
): Set<FeatureFlagProvider> {
val providers = HashSet<FeatureFlagProvider>()
//TODO change this condition?
if (buildMeta.isDebug) {
providers.add(runtimeFeatureFlagProvider)
} else {
if (buildType == BuildType.RELEASE) {
providers.add(buildtimeFeatureFlagProvider)
} else {
providers.add(runtimeFeatureFlagProvider)
}
return providers
}

27
libraries/featureflag/test/build.gradle.kts

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
id("io.element.android-library")
}
android {
namespace = "io.element.android.libraries.featureflag.test"
dependencies {
api(projects.libraries.featureflag.api)
}
}

36
libraries/featureflag/test/src/main/java/io/element/android/libraries/featureflag/test/FakeFeatureFlagService.kt

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.featureflag.test
import io.element.android.libraries.featureflag.api.Feature
import io.element.android.libraries.featureflag.api.FeatureFlagService
class FakeFeatureFlagService(
initialState: Map<String, Boolean> = emptyMap()
) : FeatureFlagService {
private val enabledFeatures = HashMap(initialState)
override suspend fun setFeatureEnabled(feature: Feature, enabled: Boolean): Boolean {
enabledFeatures[feature.key] = enabled
return true
}
override suspend fun isFeatureEnabled(feature: Feature): Boolean {
return enabledFeatures[feature.key] ?: feature.defaultValue
}
}

2
settings.gradle.kts

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
import java.net.URI
include(":libraries:featureflag:test")
include(":libraries:featureflag:ui")
/*

Loading…
Cancel
Save