Add isFreshInstall Boolean to allow the miration to behave in a different way for an application upgrade or a fresh install.
We cannot restore the previous code which existed because of https://github.com/element-hq/element-x-android/pull/3535
This commit is contained in:
committed by
Benoit Marty
parent
2f1866afd8
commit
71d2c1d9df
@@ -31,6 +31,7 @@ class MigrationPresenter(
|
||||
) : Presenter<MigrationState> {
|
||||
private val orderedMigrations = migrations.sortedBy { it.order }
|
||||
private val lastMigration: Int = orderedMigrations.lastOrNull()?.order ?: 0
|
||||
private var isFreshInstall = false
|
||||
|
||||
@Composable
|
||||
override fun present(): MigrationState {
|
||||
@@ -49,6 +50,7 @@ class MigrationPresenter(
|
||||
val migrationValue = migrationStoreVersion ?: return@LaunchedEffect
|
||||
if (migrationValue == -1) {
|
||||
Timber.d("Fresh install, or previous installed application did not have the migration mechanism.")
|
||||
isFreshInstall = true
|
||||
}
|
||||
if (migrationValue == lastMigration) {
|
||||
Timber.d("Current app migration version: $migrationValue. No migration needed.")
|
||||
@@ -59,7 +61,7 @@ class MigrationPresenter(
|
||||
val nextMigration = orderedMigrations.firstOrNull { it.order > migrationValue }
|
||||
if (nextMigration != null) {
|
||||
Timber.d("Current app migration version: $migrationValue. Applying migration: ${nextMigration.order}")
|
||||
nextMigration.migrate()
|
||||
nextMigration.migrate(isFreshInstall)
|
||||
migrationStore.setApplicationMigrationVersion(nextMigration.order)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ package io.element.android.features.migration.impl.migrations
|
||||
|
||||
interface AppMigration {
|
||||
val order: Int
|
||||
suspend fun migrate()
|
||||
suspend fun migrate(isFreshInstall: Boolean)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class AppMigration01(
|
||||
) : AppMigration {
|
||||
override val order: Int = 1
|
||||
|
||||
override suspend fun migrate() {
|
||||
override suspend fun migrate(isFreshInstall: Boolean) {
|
||||
logFilesRemover.perform()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class AppMigration02(
|
||||
) : AppMigration {
|
||||
override val order: Int = 2
|
||||
|
||||
override suspend fun migrate() {
|
||||
override suspend fun migrate(isFreshInstall: Boolean) {
|
||||
coroutineScope {
|
||||
for (session in sessionStore.getAllSessions()) {
|
||||
val sessionId = SessionId(session.userId)
|
||||
|
||||
@@ -21,7 +21,7 @@ class AppMigration03(
|
||||
) : AppMigration {
|
||||
override val order: Int = 3
|
||||
|
||||
override suspend fun migrate() {
|
||||
migration01.migrate()
|
||||
override suspend fun migrate(isFreshInstall: Boolean) {
|
||||
migration01.migrate(isFreshInstall)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class AppMigration04(
|
||||
}
|
||||
override val order: Int = 4
|
||||
|
||||
override suspend fun migrate() {
|
||||
override suspend fun migrate(isFreshInstall: Boolean) {
|
||||
runCatchingExceptions { context.getDatabasePath(NOTIFICATION_FILE_NAME).delete() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class AppMigration05(
|
||||
) : AppMigration {
|
||||
override val order: Int = 5
|
||||
|
||||
override suspend fun migrate() {
|
||||
override suspend fun migrate(isFreshInstall: Boolean) {
|
||||
val allSessions = sessionStore.getAllSessions()
|
||||
for (session in allSessions) {
|
||||
if (session.sessionPath.isEmpty()) {
|
||||
|
||||
@@ -25,7 +25,7 @@ class AppMigration06(
|
||||
) : AppMigration {
|
||||
override val order: Int = 6
|
||||
|
||||
override suspend fun migrate() {
|
||||
override suspend fun migrate(isFreshInstall: Boolean) {
|
||||
val allSessions = sessionStore.getAllSessions()
|
||||
for (session in allSessions) {
|
||||
if (session.cachePath.isEmpty()) {
|
||||
|
||||
@@ -22,7 +22,7 @@ class AppMigration07(
|
||||
) : AppMigration {
|
||||
override val order: Int = 7
|
||||
|
||||
override suspend fun migrate() {
|
||||
override suspend fun migrate(isFreshInstall: Boolean) {
|
||||
logFilesRemover.perform { file ->
|
||||
file.name.startsWith("logs-")
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@ import io.element.android.features.migration.impl.migrations.AppMigration
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||
import io.element.android.tests.testutils.lambda.LambdaNoParamRecorder
|
||||
import io.element.android.tests.testutils.lambda.LambdaOneParamRecorder
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
@@ -48,13 +50,18 @@ class MigrationPresenterTest {
|
||||
assertThat(store.applicationMigrationVersion().first()).isEqualTo(migrations.maxOf { it.order })
|
||||
}
|
||||
for (migration in migrations) {
|
||||
migration.migrateLambda.assertions().isCalledOnce()
|
||||
migration.migrateLambda.assertions().isCalledOnce().with(value(true))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - no migration should occurs if ApplicationMigrationVersion is the last one`() = runTest {
|
||||
val migrations = (1..10).map { FakeAppMigration(it) }
|
||||
val migrations = (1..10).map {
|
||||
FakeAppMigration(
|
||||
order = it,
|
||||
migrateLambda = lambdaRecorder<Boolean, Unit> { lambdaError() },
|
||||
)
|
||||
}
|
||||
val store = InMemoryMigrationStore(migrations.maxOf { it.order })
|
||||
val presenter = createPresenter(
|
||||
migrationStore = store,
|
||||
@@ -90,7 +97,7 @@ class MigrationPresenterTest {
|
||||
consumeItemsUntilPredicate { it.migrationAction is AsyncData.Success }
|
||||
assertThat(store.applicationMigrationVersion().first()).isEqualTo(migrations.maxOf { it.order })
|
||||
for (migration in migrations) {
|
||||
migration.migrateLambda.assertions().isCalledOnce()
|
||||
migration.migrateLambda.assertions().isCalledOnce().with(value(false))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,9 +113,9 @@ private fun createPresenter(
|
||||
|
||||
private class FakeAppMigration(
|
||||
override val order: Int,
|
||||
val migrateLambda: LambdaNoParamRecorder<Unit> = lambdaRecorder { -> },
|
||||
val migrateLambda: LambdaOneParamRecorder<Boolean, Unit> = lambdaRecorder<Boolean, Unit> { },
|
||||
) : AppMigration {
|
||||
override suspend fun migrate() {
|
||||
migrateLambda()
|
||||
override suspend fun migrate(isFreshInstall: Boolean) {
|
||||
migrateLambda(isFreshInstall)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ class AppMigration01Test {
|
||||
val logsFileRemover = FakeLogFilesRemover()
|
||||
val migration = AppMigration01(logsFileRemover)
|
||||
|
||||
migration.migrate()
|
||||
migration.migrate(true)
|
||||
|
||||
logsFileRemover.performLambda.assertions().isCalledOnce()
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ class AppMigration02Test {
|
||||
)
|
||||
val migration = AppMigration02(sessionStore = sessionStore, sessionPreferenceStoreFactory = sessionPreferencesStoreFactory)
|
||||
|
||||
migration.migrate()
|
||||
migration.migrate(true)
|
||||
|
||||
// We got the session preferences store
|
||||
sessionPreferencesStoreFactory.getLambda.assertions().isCalledOnce()
|
||||
|
||||
@@ -17,7 +17,7 @@ class AppMigration03Test {
|
||||
val logsFileRemover = FakeLogFilesRemover()
|
||||
val migration = AppMigration03(migration01 = AppMigration01(logsFileRemover))
|
||||
|
||||
migration.migrate()
|
||||
migration.migrate(true)
|
||||
|
||||
logsFileRemover.performLambda.assertions().isCalledOnce()
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class AppMigration04Test {
|
||||
|
||||
val migration = AppMigration04(context)
|
||||
|
||||
migration.migrate()
|
||||
migration.migrate(true)
|
||||
|
||||
// Check that the file has been deleted
|
||||
assertThat(file.exists()).isFalse()
|
||||
|
||||
@@ -27,7 +27,7 @@ class AppMigration05Test {
|
||||
)
|
||||
)
|
||||
val migration = AppMigration05(sessionStore = sessionStore, baseDirectory = File("/a/path"))
|
||||
migration.migrate()
|
||||
migration.migrate(true)
|
||||
val storedData = sessionStore.getSession(A_SESSION_ID.value)!!
|
||||
assertThat(storedData.sessionPath).isEqualTo("/a/path/${A_SESSION_ID.value.replace(':', '_')}")
|
||||
}
|
||||
@@ -43,7 +43,7 @@ class AppMigration05Test {
|
||||
)
|
||||
)
|
||||
val migration = AppMigration05(sessionStore = sessionStore, baseDirectory = File("/a/path"))
|
||||
migration.migrate()
|
||||
migration.migrate(true)
|
||||
val storedData = sessionStore.getSession(A_SESSION_ID.value)!!
|
||||
assertThat(storedData.sessionPath).isEqualTo("/a/path/existing")
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class AppMigration06Test {
|
||||
)
|
||||
)
|
||||
val migration = AppMigration06(sessionStore = sessionStore, cacheDirectory = File("/a/path/cache"))
|
||||
migration.migrate()
|
||||
migration.migrate(true)
|
||||
val storedData = sessionStore.getSession(A_SESSION_ID.value)!!
|
||||
assertThat(storedData.cachePath).isEqualTo("/a/path/cache/AN_ID")
|
||||
}
|
||||
@@ -44,7 +44,7 @@ class AppMigration06Test {
|
||||
)
|
||||
)
|
||||
val migration = AppMigration05(sessionStore = sessionStore, baseDirectory = File("/a/path/cache"))
|
||||
migration.migrate()
|
||||
migration.migrate(true)
|
||||
val storedData = sessionStore.getSession(A_SESSION_ID.value)!!
|
||||
assertThat(storedData.cachePath).isEqualTo("/a/path/existing")
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class AppMigration07Test {
|
||||
}
|
||||
val logsFileRemover = FakeLogFilesRemover(performLambda = performLambda)
|
||||
val migration = AppMigration07(logsFileRemover)
|
||||
migration.migrate()
|
||||
migration.migrate(true)
|
||||
performLambda.assertions().isCalledOnce()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user