Skip to content

Commit

Permalink
Implementation of class level annotation and repeatable annotations f…
Browse files Browse the repository at this point in the history
…or both feature flags and parameter value overrides
  • Loading branch information
Rd4dev committed Nov 4, 2024
1 parent 1867a89 commit 1195cc1
Show file tree
Hide file tree
Showing 13 changed files with 133 additions and 67 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ android {
exceptionFormat = "full"
showCauses = true
showStackTraces = true
showStandardStreams = false
showStandardStreams = true
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,9 @@ class ProfileAndDeviceIdFragmentTest {

@Before
fun setUp() {
TestPlatformParameterModule.forceEnableEditAccountsOptionsUi(true)
// TestPlatformParameterModule.forceEnableEditAccountsOptionsUi(true)
// TestPlatformParameterModule.forceEnableLearnerStudyAnalytics(true)
TestPlatformParameterModule.forceEnableLoggingLearnerStudyIds(true)
// TestPlatformParameterModule.forceEnableLoggingLearnerStudyIds(true)
setUpTestApplicationComponent()
Intents.init()
testCoroutineDispatchers.registerIdlingResource()
Expand Down Expand Up @@ -494,9 +494,7 @@ class ProfileAndDeviceIdFragmentTest {
}
}

// learner study on
@Test
@EnableFeatureFlag("android_enable_learner_study_analytics")
fun testFragment_firstEntry_mixOfAdminAndGenericEvents_someUploaded_reportsAllEvents() {
profileTestHelper.addMoreProfiles(numProfiles = 1)
runWithLaunchedActivityAndAddedFragment {
Expand All @@ -517,11 +515,7 @@ class ProfileAndDeviceIdFragmentTest {
}
}

// learner study + log event
@Test
// @EnableFeatureFlag("android_enable_logging_learner_study_ids")
// @EnableFeatureFlag("android_enable_spotlight_ui")
@EnableFeatureFlag("android_enable_learner_study_analytics")
fun testFragment_firstEntry_reportsAllEvents_and_eventLogged_indicatorTextMentionsWaiting() {
profileTestHelper.addMoreProfiles(numProfiles = 1)
runWithLaunchedActivityAndAddedFragment {
Expand Down Expand Up @@ -643,7 +637,6 @@ class ProfileAndDeviceIdFragmentTest {
}

@Test
@EnableFeatureFlag("android_enable_learner_study_analytics")
fun testFragment_eventLogged_waitingForUpload_indicatorTextMentionsWaiting() {
runWithLaunchedActivityAndAddedFragment {
disconnectNetwork() // Ensure events are cached.
Expand Down Expand Up @@ -811,7 +804,10 @@ class ProfileAndDeviceIdFragmentTest {
}
}

// req learner study analytics + log learner study id
@Test
@EnableFeatureFlag("android_enable_logging_learner_study_ids")
@EnableFeatureFlag("android_enable_learner_study_analytics")
fun testFragment_multipleProfiles_clickShareIdsAndLogs_sendsIntentWithIdsAndLogsText() {
// Use fake time so that the generated event logs are consistent across runs.
fakeOppiaClock.setFakeTimeMode(FakeOppiaClock.FakeTimeMode.MODE_FIXED_FAKE_TIME)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ import java.io.IOException
import java.util.concurrent.TimeoutException
import javax.inject.Inject
import javax.inject.Singleton
import org.oppia.android.domain.platformparameter.PlatformParameterModule
import org.oppia.android.testing.OverrideBoolParameter

/** Tests for [StateFragment]. */
@RunWith(AndroidJUnit4::class)
Expand Down Expand Up @@ -3469,6 +3471,7 @@ class StateFragmentTest {
}

@Test
@OverrideBoolParameter("cache_latex_rendering", true)
fun testStateFragment_mathInteractions_numericExp_validAns_submissionDisplaysLatex() {
setUpTestWithLanguageSwitchingFeatureOff()
launchForExploration(TEST_EXPLORATION_ID_5, shouldSavePartialProgress = false).use { scenario ->
Expand Down Expand Up @@ -5743,7 +5746,7 @@ class StateFragmentTest {
@Singleton
@Component(
modules = [
TestModule::class, RobolectricModule::class, TestPlatformParameterModule::class,
TestModule::class, RobolectricModule::class, PlatformParameterModule::class,
TestDispatcherModule::class, ApplicationModule::class, LoggerModule::class,
ContinueModule::class, FractionInputModule::class, ItemSelectionInputModule::class,
MultipleChoiceInputModule::class, NumberWithUnitsRuleModule::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ import org.oppia.android.domain.platformparameter.PlatformParameterModule
import org.oppia.android.testing.DisableFeatureFlag
import org.oppia.android.testing.EnableFeatureFlag
import org.oppia.android.testing.OppiaTestRule
import org.oppia.android.testing.ResetFeatureFlagToDefault
import org.oppia.android.testing.RunOn
import org.oppia.android.testing.TestPlatform

Expand All @@ -113,6 +114,7 @@ import org.oppia.android.testing.TestPlatform
application = SpotlightFragmentTest.TestApplication::class,
qualifiers = "port-xxhdpi"
)
@EnableFeatureFlag("android_enable_spotlight_ui")
class SpotlightFragmentTest {
@field:[Rule JvmField]
val mockitoRule: MockitoRule = MockitoJUnit.rule()
Expand Down Expand Up @@ -150,7 +152,8 @@ class SpotlightFragmentTest {
}

@Test
@DisableFeatureFlag("android_enable_spotlight_ui")
@ResetFeatureFlagToDefault("android_enable_spotlight_ui")
// @DisableFeatureFlag("android_enable_spotlight_ui")
fun testSpotlightFragment_disableSpotlights_requestSpotlight_shouldNotShowSpotlight() {
// TestPlatformParameterModule.forceEnableSpotlightUi(false)
launch<SpotlightFragmentTestActivity>(
Expand All @@ -173,8 +176,7 @@ class SpotlightFragmentTest {
}

@Test
@DisableFeatureFlag("android_enable_spotlight_ui")
@DisableFeatureFlag("android_enable_learner_study_analytics")
// @EnableFeatureFlag("android_enable_spotlight_ui")
fun testSpotlightFragment_requestSpotlight_shouldShowSpotlight() {
// TestPlatformParameterModule.forceEnableSpotlightUi(true)
launch<SpotlightFragmentTestActivity>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ class PlatformParameterModule {
fun provideEnableDownloadsSupport(
platformParameterSingleton: PlatformParameterSingleton
): PlatformParameterValue<Boolean> {
System.out.println("In Enable downloads support")
return overriddenParameters[DOWNLOADS_SUPPORT]?.let {
PlatformParameterValue.createDefaultParameter(it as Boolean)
} ?: platformParameterSingleton.getBooleanPlatformParameter(DOWNLOADS_SUPPORT)
Expand Down Expand Up @@ -131,7 +130,6 @@ class PlatformParameterModule {
fun provideLearnerStudyAnalytics(
platformParameterSingleton: PlatformParameterSingleton
): PlatformParameterValue<Boolean> {
System.out.println("In Enable learner study analysis")
return overriddenParameters[LEARNER_STUDY_ANALYTICS]?.let {
PlatformParameterValue.createDefaultParameter(it as Boolean)
} ?: platformParameterSingleton.getBooleanPlatformParameter(LEARNER_STUDY_ANALYTICS)
Expand All @@ -154,7 +152,6 @@ class PlatformParameterModule {
fun provideLoggingLearnerStudyIds(
platformParameterSingleton: PlatformParameterSingleton
): PlatformParameterValue<Boolean> {
System.out.println("In Enable logging learner study ids")
return overriddenParameters[LOGGING_LEARNER_STUDY_IDS]?.let {
PlatformParameterValue.createDefaultParameter(it as Boolean)
} ?: platformParameterSingleton.getBooleanPlatformParameter(LOGGING_LEARNER_STUDY_IDS)
Expand All @@ -166,7 +163,9 @@ class PlatformParameterModule {
fun provideCacheLatexRendering(
platformParameterSingleton: PlatformParameterSingleton
): PlatformParameterValue<Boolean> {
return platformParameterSingleton.getBooleanPlatformParameter(CACHE_LATEX_RENDERING)
return overriddenParameters[CACHE_LATEX_RENDERING]?.let {
PlatformParameterValue.createDefaultParameter(it as Boolean)
} ?: platformParameterSingleton.getBooleanPlatformParameter(CACHE_LATEX_RENDERING)
?: PlatformParameterValue.createDefaultParameter(CACHE_LATEX_RENDERING_DEFAULT_VALUE)
}

Expand Down Expand Up @@ -223,7 +222,6 @@ class PlatformParameterModule {
fun provideEnableSpotlightUi(
platformParameterSingleton: PlatformParameterSingleton
): PlatformParameterValue<Boolean> {
System.out.println("In Enable spotlight ui")
return overriddenParameters[SPOTLIGHT_UI]?.let {
PlatformParameterValue.createDefaultParameter(it as Boolean)
} ?: platformParameterSingleton.getBooleanPlatformParameter(SPOTLIGHT_UI)
Expand Down Expand Up @@ -365,40 +363,17 @@ class PlatformParameterModule {
private val overriddenParameters = mutableMapOf<String, Any>()

fun overrideParameter(name: String, value: Any) {
println("Name: $name, value: $value")
overriddenParameters[name] = value
}

/*private var downloadsSupport = ENABLE_DOWNLOADS_SUPPORT_DEFAULT_VALUE
private var editAccountsOptionsUi = ENABLE_EDIT_ACCOUNTS_OPTIONS_UI_DEFAULT_VALUE
private var learnerStudyAnalytics = LEARNER_STUDY_ANALYTICS_DEFAULT_VALUE
private var fastLanguageSwitchingInLesson = FAST_LANGUAGE_SWITCHING_IN_LESSON_DEFAULT_VALUE
private var loggingLearnerStudyIds = LOGGING_LEARNER_STUDY_IDS_DEFAULT_VALUE
private var extraTopicTabsUi = ENABLE_EXTRA_TOPIC_TABS_UI_DEFAULT_VALUE
private var interactionConfigChangeStateRetention = ENABLE_INTERACTION_CONFIG_CHANGE_STATE_RETENTION_DEFAULT_VALUE
private var performanceMetricsCollection = ENABLE_PERFORMANCE_METRICS_COLLECTION_DEFAULT_VALUE
private var spotlightUi = ENABLE_SPOTLIGHT_UI_DEFAULT_VALUE
private var appAndOsDeprecation = ENABLE_APP_AND_OS_DEPRECATION_DEFAULT_VALUE
private var npsSurvey = ENABLE_NPS_SURVEY_DEFAULT_VALUE
private var onboardingFlowV2 = ENABLE_ONBOARDING_FLOW_V2_DEFAULT_VALUE
private var multipleClassrooms = ENABLE_MULTIPLE_CLASSROOMS_DEFAULT_VALUE
*/
/*fun overrideParameter(name: String, value: Boolean) {
when (name.lowercase()) {
"downloads_support" -> downloadsSupport = value
"edit_accounts_options_ui" -> editAccountsOptionsUi = value
"learner_study_analytics" -> learnerStudyAnalytics = value
"fast_language_switching_in_lesson" -> fastLanguageSwitchingInLesson = value
"logging_learner_study_ids" -> loggingLearnerStudyIds = value
"extra_topic_tabs_ui" -> extraTopicTabsUi = value
"interaction_config_change_state_retention" -> interactionConfigChangeStateRetention = value
"enable_performance_metrics_collection" -> performanceMetricsCollection = value
"spotlight_ui" -> spotlightUi = value
"app_and_os_deprecation" -> appAndOsDeprecation = value
"enable_nps_survey" -> npsSurvey = value
"enable_onboarding_flow_v2" -> onboardingFlowV2 = value
"enable_multiple_classrooms" -> multipleClassrooms = value
else -> throw IllegalArgumentException("Feature flag '$name' is not recognized.")
}
}*/
fun resetParameterToDefault(name: String) {
println("Resetting $name")
overriddenParameters.remove(name)
}

fun clearAllParameterOverrides() {
overriddenParameters.clear()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.oppia.android.testing

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@Repeatable
annotation class EnableFeatureFlag(val name: String)
97 changes: 84 additions & 13 deletions testing/src/main/java/org/oppia/android/testing/OppiaTestRule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,50 @@ private const val DEFAULT_ACCESSIBILITY_CHECKS_ENABLED_STATE = true
class OppiaTestRule : TestRule {

override fun apply(base: Statement?, description: Description?): Statement {
System.out.println("Enabled Feature Flags are:")
return object : Statement() {
override fun evaluate() {
val areAccessibilityChecksEnabled = description.areAccessibilityChecksEnabled()
val targetPlatforms = description.getTargetPlatforms()
val targetEnvironments = description.getTargetEnvironments()
val currentPlatform = getCurrentPlatform()
val currentEnvironment = getCurrentBuildEnvironment()
val enabledFeatureFlags = description?.getAnnotation(EnableFeatureFlag::class.java)
System.out.println("Enabled Feature Flags are: $enabledFeatureFlags")
val disabledFeatureFlags = description?.getAnnotation(DisableFeatureFlag::class.java)
System.out.println("Disabled Feature Flags are: $disabledFeatureFlags")

val eff = description?.annotations?.filterIsInstance<EnableFeatureFlag>()
val enabledFeatureFlags = extractParametersAndFeatureFlags(
description?.testClass?.annotations?.toList(), EnableFeatureFlag::class.java) +
extractParametersAndFeatureFlags(description?.annotations, EnableFeatureFlag::class.java)

val disabledFeatureFlags = extractParametersAndFeatureFlags(
description?.testClass?.annotations?.toList(), DisableFeatureFlag::class.java) +
extractParametersAndFeatureFlags(description?.annotations, DisableFeatureFlag::class.java)

val overriddenBoolParameters = extractParametersAndFeatureFlags(
description?.testClass?.annotations?.toList(), OverrideBoolParameter::class.java) +
extractParametersAndFeatureFlags(description?.annotations, OverrideBoolParameter::class.java)

val overriddenIntParameters = extractParametersAndFeatureFlags(
description?.testClass?.annotations?.toList(), OverrideIntParameter::class.java) +
extractParametersAndFeatureFlags(description?.annotations, OverrideIntParameter::class.java)

val overriddenStringParameters = extractParametersAndFeatureFlags(
description?.testClass?.annotations?.toList(), OverrideStringParameter::class.java) +
extractParametersAndFeatureFlags(description?.annotations, OverrideStringParameter::class.java)

val resetFeatureFlagToDefault = extractParametersAndFeatureFlags(
description?.annotations, ResetFeatureFlagToDefault::class.java)

val resetParameterToDefault = extractParametersAndFeatureFlags(
description?.annotations, ResetParameterToDefault::class.java)

try {
applyOverrides(eff, disabledFeatureFlags)
applyOverrides(
enabledFeatureFlags,
disabledFeatureFlags,
overriddenBoolParameters,
overriddenIntParameters,
overriddenStringParameters,
resetFeatureFlagToDefault,
resetParameterToDefault
)

when {
currentPlatform in targetPlatforms && currentEnvironment in targetEnvironments -> {
Expand Down Expand Up @@ -74,19 +101,42 @@ class OppiaTestRule : TestRule {
else -> throw AssertionError("Reached impossible state in test rule")
}
} finally {

PlatformParameterModule.clearAllParameterOverrides()
}
}
}
}

private fun applyOverrides(enabledFeatureFlag: List<EnableFeatureFlag>?, disabledFeatureFlag: DisableFeatureFlag?) {
// enabledFeatureFlag?.let { PlatformParameterModule.overrideParameter(it.name, true) }
enabledFeatureFlag?.forEach { flag ->
System.out.println("Flag name: $flag")
private fun applyOverrides(
enabledFeatureFlags: List<EnableFeatureFlag>?,
disabledFeatureFlags: List<DisableFeatureFlag>?,
overriddenBoolParameters: List<OverrideBoolParameter>?,
overriddenIntParameters: List<OverrideIntParameter>?,
overriddenStringParameters: List<OverrideStringParameter>?,
resetFeatureFlagToDefault: List<ResetFeatureFlagToDefault>?,
resetParameterToDefault: List<ResetParameterToDefault>?
) {
enabledFeatureFlags?.forEach { flag ->
PlatformParameterModule.overrideParameter(flag.name, true)
}
disabledFeatureFlag?.let { PlatformParameterModule.overrideParameter(it.name, false) }
disabledFeatureFlags?.forEach { flag ->
PlatformParameterModule.overrideParameter(flag.name, false)
}
overriddenBoolParameters?.forEach { overriddenValue ->
PlatformParameterModule.overrideParameter(overriddenValue.name, overriddenValue.value)
}
overriddenIntParameters?.forEach { overriddenValue ->
PlatformParameterModule.overrideParameter(overriddenValue.name, overriddenValue.value)
}
overriddenStringParameters?.forEach { overriddenValue ->
PlatformParameterModule.overrideParameter(overriddenValue.name, overriddenValue.value)
}
resetFeatureFlagToDefault?.forEach { resetFeatureFlag ->
PlatformParameterModule.resetParameterToDefault(resetFeatureFlag.name)
}
resetParameterToDefault?.forEach { resetParameter ->
PlatformParameterModule.resetParameterToDefault(resetParameter.name)
}
}

private fun getCurrentPlatform(): TestPlatform {
Expand Down Expand Up @@ -157,5 +207,26 @@ class OppiaTestRule : TestRule {
private fun <T> Class<T>.areAccessibilityTestsEnabledForClass(): Boolean {
return getAnnotation(DisableAccessibilityChecks::class.java) == null
}

inline fun <reified T : Annotation> extractParametersAndFeatureFlags(
annotations: Collection<Annotation>?,
featureFlagClass: Class<T>
): List<T> {
return annotations?.flatMap { annotation ->
when (annotation) {
is T -> listOf(annotation)
else -> {
val containerClass = annotation.annotationClass.java
if (containerClass.simpleName == "Container") {
val valueMethod = containerClass.getDeclaredMethod("value")
val flagsArray = valueMethod.invoke(annotation) as Array<*>
flagsArray.filterIsInstance(featureFlagClass)
} else {
emptyList()
}
}
}
} ?: emptyList()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.oppia.android.testing

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Repeatable
annotation class OverrideBoolParameter(val name: String, val value: Boolean)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.oppia.android.testing

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Repeatable
annotation class OverrideIntParameter(val name: String, val value: Int)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.oppia.android.testing

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Repeatable
annotation class OverrideStringParameter(val name: String, val value: String)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.oppia.android.testing

@Target(AnnotationTarget.FUNCTION)
@Repeatable
annotation class ResetParameterToDefault(val name: String)
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ annotation class EnableSpotlightUi
const val SPOTLIGHT_UI = "android_enable_spotlight_ui"

/** Default value for the feature flag corresponding to [EnableSpotlightUi]. */
const val ENABLE_SPOTLIGHT_UI_DEFAULT_VALUE = true
const val ENABLE_SPOTLIGHT_UI_DEFAULT_VALUE = false

/**
* Qualifier for the feature flag that controls whether input interaction state is correctly
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ annotation class CacheLatexRendering
const val CACHE_LATEX_RENDERING = "cache_latex_rendering"

/** Default value for whether to cache LaTeX rendering using Glide. */
const val CACHE_LATEX_RENDERING_DEFAULT_VALUE = true
const val CACHE_LATEX_RENDERING_DEFAULT_VALUE = false

/**
* Qualifier for the platform parameter that controls the time interval in minutes of uploading
Expand Down

0 comments on commit 1195cc1

Please sign in to comment.