diff --git a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/MigrationPresenter.kt b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/MigrationPresenter.kt index 7edbc5389f..d4e6d6dc37 100644 --- a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/MigrationPresenter.kt +++ b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/MigrationPresenter.kt @@ -31,6 +31,7 @@ class MigrationPresenter( ) : Presenter { 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) } } diff --git a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration.kt b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration.kt index a0327e8b09..f14ec89dbe 100644 --- a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration.kt +++ b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration.kt @@ -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) } diff --git a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration01.kt b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration01.kt index 048a400f6c..88fdb16b9e 100644 --- a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration01.kt +++ b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration01.kt @@ -22,7 +22,7 @@ class AppMigration01( ) : AppMigration { override val order: Int = 1 - override suspend fun migrate() { + override suspend fun migrate(isFreshInstall: Boolean) { logFilesRemover.perform() } } diff --git a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration02.kt b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration02.kt index 44f4806c65..0ba2712427 100644 --- a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration02.kt +++ b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration02.kt @@ -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) diff --git a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration03.kt b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration03.kt index 0cb3573954..e24e18a205 100644 --- a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration03.kt +++ b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration03.kt @@ -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) } } diff --git a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration04.kt b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration04.kt index 8ab4921038..f1f16b7a97 100644 --- a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration04.kt +++ b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration04.kt @@ -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() } } } diff --git a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration05.kt b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration05.kt index 109ff7e0b7..2a60822c5d 100644 --- a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration05.kt +++ b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration05.kt @@ -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()) { diff --git a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration06.kt b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration06.kt index 2eb98b9e5f..be3050f919 100644 --- a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration06.kt +++ b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration06.kt @@ -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()) { diff --git a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration07.kt b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration07.kt index fe88817796..5367323b75 100644 --- a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration07.kt +++ b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration07.kt @@ -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-") } diff --git a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/MigrationPresenterTest.kt b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/MigrationPresenterTest.kt index 635a06f028..e5898ea0dd 100644 --- a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/MigrationPresenterTest.kt +++ b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/MigrationPresenterTest.kt @@ -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 { 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 = lambdaRecorder { -> }, + val migrateLambda: LambdaOneParamRecorder = lambdaRecorder { }, ) : AppMigration { - override suspend fun migrate() { - migrateLambda() + override suspend fun migrate(isFreshInstall: Boolean) { + migrateLambda(isFreshInstall) } } diff --git a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration01Test.kt b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration01Test.kt index 580be7d705..6e1b663e3c 100644 --- a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration01Test.kt +++ b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration01Test.kt @@ -17,7 +17,7 @@ class AppMigration01Test { val logsFileRemover = FakeLogFilesRemover() val migration = AppMigration01(logsFileRemover) - migration.migrate() + migration.migrate(true) logsFileRemover.performLambda.assertions().isCalledOnce() } diff --git a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration02Test.kt b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration02Test.kt index fb7dbf5281..08c10160b8 100644 --- a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration02Test.kt +++ b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration02Test.kt @@ -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() diff --git a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration03Test.kt b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration03Test.kt index e4911faaa5..0f4db78aa2 100644 --- a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration03Test.kt +++ b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration03Test.kt @@ -17,7 +17,7 @@ class AppMigration03Test { val logsFileRemover = FakeLogFilesRemover() val migration = AppMigration03(migration01 = AppMigration01(logsFileRemover)) - migration.migrate() + migration.migrate(true) logsFileRemover.performLambda.assertions().isCalledOnce() } diff --git a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration04Test.kt b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration04Test.kt index f272dadc22..68cbfde689 100644 --- a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration04Test.kt +++ b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration04Test.kt @@ -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() diff --git a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration05Test.kt b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration05Test.kt index af71905635..ff5b8cd40a 100644 --- a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration05Test.kt +++ b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration05Test.kt @@ -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") } diff --git a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration06Test.kt b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration06Test.kt index 095085cd17..e7e15ba821 100644 --- a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration06Test.kt +++ b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration06Test.kt @@ -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") } diff --git a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration07Test.kt b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration07Test.kt index a375ef8563..a2575b32df 100644 --- a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration07Test.kt +++ b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration07Test.kt @@ -24,7 +24,7 @@ class AppMigration07Test { } val logsFileRemover = FakeLogFilesRemover(performLambda = performLambda) val migration = AppMigration07(logsFileRemover) - migration.migrate() + migration.migrate(true) performLambda.assertions().isCalledOnce() } }