Skip to content

Commit

Permalink
Fix #3322: Platform parameter singleton and Generic Interface (#3323)
Browse files Browse the repository at this point in the history
* This PR introduces new Proto Classes which will be used to implement Platform Parameter project in Oppia-Android. This PR will is reffered as PR-1.1 in the Milestones

* Lint check correction

* Removing unnecessary spaces

* Changed the name of Parameter class to PlatformParameter and included the oneof type field in ParameterWithName

* Changed the names of all the other classes to include PlatformParameter in their name

* nit space change

* Reverting back to previous structure

* Suggested changes by Ben about spacing, renaming, docs and removing PlatformParameterMap

* Modifying BUILD.bazel to include platform_parameter.proto

* Changed the visibility in BUILD.bazel

* removed unnecessary visibility in BUILD.bazel

* Nit indentation change

* Suggested changes to remove the PlatformParameterWithName message and use only one PlatformParameter message everywhere

* Added a Singleton and Generic Interface to help with Providing Platform Parameters

* Added PlatformParameterSingletonTest and tweaked PlatformParameterSingleton

* Added new tests and tweaked the documentation to include KDBlocks

* Adding the dependency over PlatformParameter Proto Classes

* Using a default setter for platformParameterMap, and changed the tests to have a constant mockPlatformParameterMap instead of creating it again. Also changed the KDocs for generic interface

* Lint checks

* Renaming variables and changing KDocs

* Replaced the use of generic getter function to three separate functions for String/Int/Boolean type parameters. Also updated the tests accordingly

* Modified test cases to include check for double initialization of platformParameterMap and also to check that singleton returns null in case the wrong type of Parameter is asked

* Nit spacing changes

* using assertThat().isNotEqualTo() in place of current assert statements also correct lint checks

* Lint check

* Rearrange imports with ktlint

* KDoc changes, Renamed generic Interface to PlatformParameterValue and used PlatformParameter.newBuilder() instead of getDefaultInstance in the mockPlatformParameterMap

* Bazel changes for including PlatformParameter in the KDoc of PlatformParameterValue Interface

* Nit fix to prevent type inference warning

* Reverted auto generated changes

* Changed all the KDoc Format as suggested

* Changed the approach to have an PlatformParameterSingleton interface and its Impl. Also changed the tests accordingly

* Nit spacing changes

* Using mutableMap instead for PlatformParameterMap in Singleton
  • Loading branch information
Arjupta committed Jul 7, 2021
1 parent 9e14a32 commit a237d00
Show file tree
Hide file tree
Showing 6 changed files with 292 additions and 0 deletions.
1 change: 1 addition & 0 deletions domain/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ kt_android_library(
"//domain/src/main/java/org/oppia/android/domain/util:retriever",
"//model:exploration_checkpoint_java_proto_lite",
"//model:onboarding_java_proto_lite",
"//model:platform_parameter_java_proto_lite",
"//model:question_java_proto_lite",
"//model:topic_java_proto_lite",
"//third_party:androidx_work_work-runtime-ktx",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.oppia.android.domain.platformparameter

import org.oppia.android.app.model.PlatformParameter
import org.oppia.android.util.platformparameter.PlatformParameterSingleton
import org.oppia.android.util.platformparameter.PlatformParameterValue
import javax.inject.Inject
import javax.inject.Singleton

/** Singleton which helps in storing and providing Platform Parameters at runtime. */
@Singleton
class PlatformParameterSingletonImpl @Inject constructor() : PlatformParameterSingleton {
private val platformParameterMap = mutableMapOf<String, PlatformParameter>()

override fun getPlatformParameterMap() = platformParameterMap

override fun setPlatformParameterMap(platformParameterMap: Map<String, PlatformParameter>) {
if (this.platformParameterMap.isEmpty()) this.platformParameterMap.putAll(platformParameterMap)
}

override fun getStringPlatformParameter(
platformParameterName: String
): PlatformParameterValue<String>? {
if (platformParameterMap.isEmpty()) return null
val parameter = platformParameterMap[platformParameterName] ?: return null
if (!parameter.valueTypeCase.equals(PlatformParameter.ValueTypeCase.STRING)) return null
return object : PlatformParameterValue<String> {
override val value: String
get() = parameter.string
}
}

override fun getIntegerPlatformParameter(
platformParameterName: String
): PlatformParameterValue<Int>? {
if (platformParameterMap.isEmpty()) return null
val parameter = platformParameterMap[platformParameterName] ?: return null
if (!parameter.valueTypeCase.equals(PlatformParameter.ValueTypeCase.INTEGER)) return null
return object : PlatformParameterValue<Int> {
override val value: Int
get() = parameter.integer
}
}

override fun getBooleanPlatformParameter(
platformParameterName: String
): PlatformParameterValue<Boolean>? {
if (platformParameterMap.isEmpty()) return null
val parameter = platformParameterMap[platformParameterName] ?: return null
if (!parameter.valueTypeCase.equals(PlatformParameter.ValueTypeCase.BOOLEAN)) return null
return object : PlatformParameterValue<Boolean> {
override val value: Boolean
get() = parameter.boolean
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package org.oppia.android.domain.platformparameter

import android.app.Application
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import dagger.BindsInstance
import dagger.Component
import dagger.Module
import dagger.Provides
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.oppia.android.app.model.PlatformParameter
import org.oppia.android.util.platformparameter.PlatformParameterSingleton
import org.oppia.android.util.platformparameter.PlatformParameterValue
import org.robolectric.annotation.Config
import org.robolectric.annotation.LooperMode
import javax.inject.Inject
import javax.inject.Singleton

private const val STRING_PLATFORM_PARAMETER_NAME = "string_platform_parameter_name"
private const val STRING_PLATFORM_PARAMETER_VALUE = "string_platform_parameter_value"

private const val INTEGER_PLATFORM_PARAMETER_NAME = "integer_platform_parameter_name"
private const val INTEGER_PLATFORM_PARAMETER_VALUE = 1

private const val BOOLEAN_PLATFORM_PARAMETER_NAME = "boolean_platform_parameter_name"
private const val BOOLEAN_PLATFORM_PARAMETER_VALUE = true

private const val INCORRECT_PLATFORM_PARAMETER_NAME = "incorrect_platform_parameter_name"

/**
* [PlatformParameterSingletonTest] verifies the working of [PlatformParameterSingleton] by testing
* the [PlatformParameterValue] received in different cases
*/
@RunWith(AndroidJUnit4::class)
@LooperMode(LooperMode.Mode.PAUSED)
@Config(application = PlatformParameterSingletonTest.TestApplication::class)
class PlatformParameterSingletonTest {

@Inject
lateinit var platformParameterSingleton: PlatformParameterSingleton

private val mockPlatformParameterMap by lazy {
val stringPlatformParameter = PlatformParameter.newBuilder()
.setString(STRING_PLATFORM_PARAMETER_VALUE).build()
val integerPlatformParameter = PlatformParameter.newBuilder()
.setInteger(INTEGER_PLATFORM_PARAMETER_VALUE).build()
val booleanPlatformParameter = PlatformParameter.newBuilder()
.setBoolean(BOOLEAN_PLATFORM_PARAMETER_VALUE).build()

mapOf<String, PlatformParameter>(
STRING_PLATFORM_PARAMETER_NAME to stringPlatformParameter,
INTEGER_PLATFORM_PARAMETER_NAME to integerPlatformParameter,
BOOLEAN_PLATFORM_PARAMETER_NAME to booleanPlatformParameter,
)
}

@Before
fun setUp() {
setUpTestApplicationComponent()
}

@Test
fun testSingleton_initPlatformParameterMap_isEmpty() {
assertThat(platformParameterSingleton.getPlatformParameterMap()).isEmpty()
}

@Test
fun testSingleton_initPlatformParameterMap_isNotEmpty() {
assertThat(platformParameterSingleton.getPlatformParameterMap()).isEmpty()
platformParameterSingleton.setPlatformParameterMap(mockPlatformParameterMap)
assertThat(platformParameterSingleton.getPlatformParameterMap()).isNotEmpty()
}

@Test
fun testSingleton_initPlatformParameterMapTwice_checkIsNotUpdatedTwice() {
platformParameterSingleton.setPlatformParameterMap(mockPlatformParameterMap)
assertThat(platformParameterSingleton.getPlatformParameterMap()).isNotEmpty()

val emptyPlatformParameterMap = mapOf<String, PlatformParameter>()
platformParameterSingleton.setPlatformParameterMap(emptyPlatformParameterMap)

assertThat(
platformParameterSingleton.getPlatformParameterMap()
).isNotEqualTo(emptyPlatformParameterMap)
assertThat(
platformParameterSingleton.getPlatformParameterMap()
).isEqualTo(mockPlatformParameterMap)
}

@Test
fun testSingleton_initPlatformParameterMap_retrieveStringParameter_verifyItsValue() {
platformParameterSingleton.setPlatformParameterMap(mockPlatformParameterMap)
val stringPlatformParameter = platformParameterSingleton.getStringPlatformParameter(
STRING_PLATFORM_PARAMETER_NAME
)
assertThat(stringPlatformParameter?.value).isEqualTo(STRING_PLATFORM_PARAMETER_VALUE)
}

@Test
fun testSingleton_initPlatformParameterMap_retrieveIntegerParameter_verifyItsValue() {
platformParameterSingleton.setPlatformParameterMap(mockPlatformParameterMap)
val integerPlatformParameter = platformParameterSingleton.getIntegerPlatformParameter(
INTEGER_PLATFORM_PARAMETER_NAME
)
assertThat(integerPlatformParameter?.value).isEqualTo(INTEGER_PLATFORM_PARAMETER_VALUE)
}

@Test
fun testSingleton_initPlatformParameterMap_retrieveBooleanParameter_verifyItsValue() {
platformParameterSingleton.setPlatformParameterMap(mockPlatformParameterMap)
val booleanPlatformParameter = platformParameterSingleton.getBooleanPlatformParameter(
BOOLEAN_PLATFORM_PARAMETER_NAME
)
assertThat(booleanPlatformParameter?.value).isEqualTo(BOOLEAN_PLATFORM_PARAMETER_VALUE)
}

@Test
fun testSingleton_initPlatformParameterMap_retrieveIncorrectNamedParameter_verifyIsNull() {
platformParameterSingleton.setPlatformParameterMap(mockPlatformParameterMap)
val incorrectPlatformParameter = platformParameterSingleton.getStringPlatformParameter(
INCORRECT_PLATFORM_PARAMETER_NAME
)
assertThat(incorrectPlatformParameter).isNull()
}

@Test
fun testSingleton_initPlatformParameterMap_retrieveIncorrectTypeParameter_verifyIsNull() {
platformParameterSingleton.setPlatformParameterMap(mockPlatformParameterMap)
val incorrectPlatformParameter = platformParameterSingleton.getStringPlatformParameter(
BOOLEAN_PLATFORM_PARAMETER_NAME
)
assertThat(incorrectPlatformParameter).isNull()
}

private fun setUpTestApplicationComponent() {
ApplicationProvider.getApplicationContext<TestApplication>().inject(this)
}

@Module
class TestModule {
@Provides
fun providePlatformParameterSingleton(
platformParameterSingletonImpl: PlatformParameterSingletonImpl
): PlatformParameterSingleton = platformParameterSingletonImpl
}

// TODO(#89): Move this to a common test application component.
@Singleton
@Component(
modules = [TestModule::class]
)
interface TestApplicationComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun setApplication(application: Application): Builder
fun build(): PlatformParameterSingletonTest.TestApplicationComponent
}

fun inject(platformParameterSingletonTest: PlatformParameterSingletonTest)
}

class TestApplication : Application() {
private val component: PlatformParameterSingletonTest.TestApplicationComponent by lazy {
DaggerPlatformParameterSingletonTest_TestApplicationComponent.builder()
.setApplication(this)
.build()
}

fun inject(platformParameterSingletonTest: PlatformParameterSingletonTest) {
component.inject(platformParameterSingletonTest)
}
}
}
1 change: 1 addition & 0 deletions utility/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ kt_android_library(
"//app:crashlytics",
"//app:crashlytics_deps",
"//model:event_logger_java_proto_lite",
"//model:platform_parameter_java_proto_lite",
"//third_party:androidx_appcompat_appcompat",
"//third_party:androidx_room_room-runtime",
"//third_party:androidx_work_work-runtime",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.oppia.android.util.platformparameter

import org.oppia.android.app.model.PlatformParameter

/** Singleton which helps in storing and providing Platform Parameters at runtime. */
interface PlatformParameterSingleton {

/**
* Gets the current platformParameterMap.
*
* @return [Map<String, PlatformParameter>]
*/
fun getPlatformParameterMap(): Map<String, PlatformParameter>

/**
* Initializes a platformParameterMap in case it is empty.
*
* @param platformParameterMap [Map<String, PlatformParameter>]
* @return [Unit]
*/
fun setPlatformParameterMap(platformParameterMap: Map<String, PlatformParameter>)

/**
* Retrieves a String type Platform Parameter, if it exists in the platformParameterMap.
*
* @param platformParameterName [String], Name of the String type Platform Parameter.
* @return [PlatformParameterValue]? which contains the value for String type Platform Parameter
*/
fun getStringPlatformParameter(platformParameterName: String): PlatformParameterValue<String>?

/**
* Retrieves a Integer type Platform Parameter, if it exists in the platformParameterMap.
*
* @param platformParameterName [String], Name of the Integer type Platform Parameter.
* @return [PlatformParameterValue]? which contains the value for Integer type Platform Parameter
*/
fun getIntegerPlatformParameter(platformParameterName: String): PlatformParameterValue<Int>?

/**
* Retrieves a Boolean type Platform Parameter, if it exists in the platformParameterMap.
*
* @param platformParameterName [String], Name of the Boolean type Platform Parameter.
* @return [PlatformParameterValue]? which contains the value for Boolean type Platform Parameter
*/
fun getBooleanPlatformParameter(platformParameterName: String): PlatformParameterValue<Boolean>?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.oppia.android.util.platformparameter

import org.oppia.android.app.model.PlatformParameter

/**
* Generic interface that is used to provide platform parameter values corresponding to the
* [PlatformParameter] proto values. Objects that implement this interface will override the [value]
* property to store the actual platform parameter value.
*/
interface PlatformParameterValue<T> {
val value: T
}

0 comments on commit a237d00

Please sign in to comment.