Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #5399: Fix tests in LoggingIdentifierControllerTest #5409

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.oppia.android.domain.oppialogger

import android.app.Application
import android.app.Instrumentation
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.google.common.truth.Truth.assertThat
import com.google.protobuf.MessageLite
import dagger.BindsInstance
Expand Down Expand Up @@ -73,6 +75,7 @@ class LoggingIdentifierControllerTest {

@Before
fun setUp() {
TestLoggingIdentifierModule.applicationIdSeed = INITIAL_APPLICATION_ID
setUpTestApplicationComponent()
}

Expand All @@ -99,7 +102,8 @@ class LoggingIdentifierControllerTest {
@Test
fun testGetInstallationId_secondAppOpen_providerReturnsSameInstallationIdValue() {
monitorFactory.ensureDataProviderExecutes(loggingIdentifierController.getInstallationId())
setUpTestApplicationComponent() // Simulate an app re-open.
TestLoggingIdentifierModule.applicationIdSeed = SECOND_APP_OPEN_APPLICATION_ID
setUpNewTestApplicationComponent() // Simulate an app re-open with a new app ID.

val installationId =
monitorFactory.waitForNextSuccessfulResult(loggingIdentifierController.getInstallationId())
Expand All @@ -110,15 +114,35 @@ class LoggingIdentifierControllerTest {

@Test
fun testGetInstallationId_secondAppOpen_emptiedDatabase_providerReturnsEmptyString() {
// Simulate initing the installation ID, then emptying/corrupting it, then reopening the app.
monitorFactory.ensureDataProviderExecutes(loggingIdentifierController.getInstallationId())
writeFileCache("device_context_database", DeviceContextDatabase.getDefaultInstance())
TestLoggingIdentifierModule.applicationIdSeed = SECOND_APP_OPEN_APPLICATION_ID
setUpNewTestApplicationComponent() // Simulate an app re-open with a new app ID.

val installationId =
monitorFactory.waitForNextSuccessfulResult(loggingIdentifierController.getInstallationId())

// The installation ID is empty since the database was overwritten.
// If the file was emptied, no installation ID can be loaded (this is a critical failure case).
assertThat(installationId).isEmpty()
}

@Test
fun testGetInstallationId_secondAppOpen_deletedDatabase_providerReturnsNewInstallationIdValue() {
// Simulate initing the installation ID, then deleting it, then reopening the app.
monitorFactory.ensureDataProviderExecutes(loggingIdentifierController.getInstallationId())
deleteCacheFile("device_context_database")
TestLoggingIdentifierModule.applicationIdSeed = SECOND_APP_OPEN_APPLICATION_ID
setUpNewTestApplicationComponent() // Simulate an app re-open with a new app ID.

val installationId =
monitorFactory.waitForNextSuccessfulResult(loggingIdentifierController.getInstallationId())

// It should seem like a reinstallation since the app's data has been cleared after restarting.
assertThat(installationId).isEqualTo("a52e69fcfedc")
assertThat(installationId.length).isEqualTo(12)
}

@Test
fun testFetchInstallationId_initialAppState_returnsNewInstallationIdValue() {
val installationId = fetchSuccessfulAsyncValue(loggingIdentifierController::fetchInstallationId)
Expand All @@ -130,7 +154,8 @@ class LoggingIdentifierControllerTest {
@Test
fun testFetchInstallationId_secondAppOpen_returnsSameInstallationIdValue() {
monitorFactory.ensureDataProviderExecutes(loggingIdentifierController.getInstallationId())
setUpTestApplicationComponent() // Simulate an app re-open.
TestLoggingIdentifierModule.applicationIdSeed = SECOND_APP_OPEN_APPLICATION_ID
setUpNewTestApplicationComponent() // Simulate an app re-open with a new app ID.

val installationId = fetchSuccessfulAsyncValue(loggingIdentifierController::fetchInstallationId)

Expand All @@ -140,14 +165,34 @@ class LoggingIdentifierControllerTest {

@Test
fun testFetchInstallationId_secondAppOpen_emptiedDatabase_returnsNull() {
// Simulate initing the installation ID, then emptying/corrupting it, then reopening the app.
monitorFactory.ensureDataProviderExecutes(loggingIdentifierController.getInstallationId())
writeFileCache("device_context_database", DeviceContextDatabase.getDefaultInstance())
TestLoggingIdentifierModule.applicationIdSeed = SECOND_APP_OPEN_APPLICATION_ID
setUpNewTestApplicationComponent() // Simulate an app re-open with a new app ID.

val installationId = fetchSuccessfulAsyncValue(loggingIdentifierController::fetchInstallationId)

// The installation ID is null since the database was overwritten.
// If the file was emptied, no installation ID can be loaded (this is a critical failure case).
assertThat(installationId).isNull()
}

@Test
fun testFetchInstallationId_secondAppOpen_deletedDatabase_returnsNewInstallationIdValue() {
// Simulate initing the installation ID, then deleting it, then reopening the app.
monitorFactory.ensureDataProviderExecutes(loggingIdentifierController.getInstallationId())
deleteCacheFile("device_context_database")
TestLoggingIdentifierModule.applicationIdSeed = SECOND_APP_OPEN_APPLICATION_ID
setUpNewTestApplicationComponent() // Simulate an app re-open with a new app ID.
monitorFactory.ensureDataProviderExecutes(loggingIdentifierController.getInstallationId())

val installationId = fetchSuccessfulAsyncValue(loggingIdentifierController::fetchInstallationId)

// The installation ID is null since the database was overwritten.
assertThat(installationId).isEqualTo("a52e69fcfedc")
assertThat(installationId?.length).isEqualTo(12)
}

@Test
fun testGetSessionId_initialState_returnsRandomId() {
val sessionIdProvider = loggingIdentifierController.getSessionId()
Expand All @@ -167,6 +212,19 @@ class LoggingIdentifierControllerTest {
assertThat(sessionId).isEqualTo("4d0a66f3-82b6-3aa9-8f61-140bdd5f49d3")
}

@Test
fun testGetSessionId_secondAppOpen_returnsNewRandomId() {
monitorFactory.ensureDataProviderExecutes(loggingIdentifierController.getSessionId())
TestLoggingIdentifierModule.applicationIdSeed = SECOND_APP_OPEN_APPLICATION_ID
setUpNewTestApplicationComponent() // Simulate an app re-open with a new app ID.

val sessionIdProvider = loggingIdentifierController.getSessionId()

// The second call should return the same ID (since the ID doesn't automatically change).
val sessionId = monitorFactory.waitForNextSuccessfulResult(sessionIdProvider)
assertThat(sessionId).isEqualTo("18c2816d-f7ad-312f-b696-d3fdd51f2e92")
}

@Test
fun testGetSessionIdFlow_initialState_returnsFlowWithRandomId() {
val sessionIdFlow = loggingIdentifierController.getSessionIdFlow()
Expand Down Expand Up @@ -255,6 +313,10 @@ class LoggingIdentifierControllerTest {
getCacheFile(cacheName).writeBytes(value.toByteArray())
}

private fun deleteCacheFile(cacheName: String) {
check(getCacheFile(cacheName).delete()) { "Failed to delete: $cacheName." }
}

private fun getCacheFile(cacheName: String) = File(context.filesDir, "$cacheName.cache")

private fun File.writeBytes(data: ByteArray) {
Expand Down Expand Up @@ -292,6 +354,17 @@ class LoggingIdentifierControllerTest {
ApplicationProvider.getApplicationContext<TestApplication>().inject(this)
}

private fun setUpNewTestApplicationComponent() {
createNewTestApplication().inject(this)
}

private fun createNewTestApplication(): TestApplication {
return Instrumentation.newApplication(
TestApplication::class.java,
InstrumentationRegistry.getInstrumentation().targetContext
) as TestApplication
}

// TODO(#89): Move this to a common test application component.
@Module
class TestModule {
Expand Down Expand Up @@ -327,12 +400,12 @@ class LoggingIdentifierControllerTest {
@Module
class TestLoggingIdentifierModule {
companion object {
internal const val applicationIdSeed = 1L
internal var applicationIdSeed: Long? = null
}

@Provides
@ApplicationIdSeed
fun provideApplicationIdSeed(): Long = applicationIdSeed
fun provideApplicationIdSeed(): Long = applicationIdSeed!! // Fail if not initialized.
}

@Module
Expand Down Expand Up @@ -398,4 +471,9 @@ class LoggingIdentifierControllerTest {

override fun getDataProvidersInjector(): DataProvidersInjector = component
}

companion object {
private const val INITIAL_APPLICATION_ID = 1L
private const val SECOND_APP_OPEN_APPLICATION_ID = 2L
}
}
Loading