Skip to content

Commit 058de77

Browse files
Merge pull request #9826 from rafaeltonholo/fix/9825/fix-app-crash
fix: db migration to version 90 crashing the app and causing database wipe
2 parents 1877d84 + b2033cb commit 058de77

File tree

3 files changed

+64
-16
lines changed

3 files changed

+64
-16
lines changed

feature/navigation/drawer/dropdown/src/main/kotlin/net/thunderbird/feature/navigation/drawer/dropdown/domain/usecase/GetDisplayTreeFolder.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package net.thunderbird.feature.navigation.drawer.dropdown.domain.usecase
33
import kotlinx.collections.immutable.persistentListOf
44
import kotlinx.collections.immutable.toImmutableList
55
import net.thunderbird.core.logging.Logger
6+
import net.thunderbird.feature.mail.folder.api.FOLDER_DEFAULT_PATH_DELIMITER
67
import net.thunderbird.feature.mail.folder.api.Folder
78
import net.thunderbird.feature.mail.folder.api.FolderPathDelimiter
89
import net.thunderbird.feature.mail.folder.api.FolderType
@@ -28,7 +29,7 @@ internal class GetDisplayTreeFolder(
2829
)
2930
}
3031

31-
val pathDelimiter = folders.first().pathDelimiter
32+
val pathDelimiter = folders.firstOrNull()?.pathDelimiter ?: FOLDER_DEFAULT_PATH_DELIMITER
3233
val accountFolders = folders.filterIsInstance<MailDisplayFolder>().map {
3334
val path = flattenPath(it.folder.name, pathDelimiter, maxDepth)
3435
logger.debug { "Flattened path for ${it.folder.name}$path" }

legacy/storage/src/main/java/com/fsck/k9/storage/migrations/MigrationTo90.kt

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import net.thunderbird.core.android.account.LegacyAccountDto
2121
import net.thunderbird.core.common.mail.Protocols
2222
import net.thunderbird.core.logging.Logger
2323
import net.thunderbird.core.logging.legacy.Log
24+
import okio.IOException
2425
import org.intellij.lang.annotations.Language
2526
import org.koin.core.component.KoinComponent
2627
import org.koin.core.component.inject
@@ -55,22 +56,26 @@ internal class MigrationTo90(
5556
try {
5657
logger.verbose(TAG) { "fetching IMAP prefix" }
5758
imapStore.fetchImapPrefix()
58-
} catch (e: AuthenticationFailedException) {
59-
logger.warn(TAG, e) { "failed to fetch IMAP prefix. skipping db migration" }
60-
return
61-
}
62-
63-
val imapPrefix = imapStore.combinedPrefix
59+
val imapPrefix = imapStore.combinedPrefix
60+
61+
if (imapPrefix?.isNotBlank() == true) {
62+
logger.verbose(TAG) { "Imap Prefix ($imapPrefix) detected, updating folder's server_id" }
63+
val query = buildQuery(imapPrefix)
64+
db.execSQL(query)
65+
} else {
66+
logger.verbose(TAG) { "No Imap Prefix detected, skipping db migration" }
67+
}
6468

65-
if (imapPrefix?.isNotBlank() == true) {
66-
logger.verbose(TAG) { "Imap Prefix ($imapPrefix) detected, updating folder's server_id" }
67-
val query = buildQuery(imapPrefix)
68-
db.execSQL(query)
69-
} else {
70-
logger.verbose(TAG) { "No Imap Prefix detected, skipping db migration" }
69+
logger.verbose(TAG) { "completed db migration to version 90 for account ${account.uuid}" }
70+
} catch (e: AuthenticationFailedException) {
71+
logger.warn(TAG, e) {
72+
"failed to fetch IMAP prefix due to authentication error. skipping db migration"
73+
}
74+
} catch (e: IOException) {
75+
logger.warn(TAG, e) {
76+
"failed to fetch IMAP prefix due to network error. skipping db migration"
77+
}
7178
}
72-
73-
logger.verbose(TAG) { "completed db migration to version 90 for account ${account.uuid}" }
7479
}
7580

7681
private fun createImapStore(account: LegacyAccountDto): ImapStore {

legacy/storage/src/test/java/com/fsck/k9/storage/migrations/MigrationTo90Test.kt

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import com.fsck.k9.mail.store.imap.ImapStoreSettings
1717
import com.fsck.k9.mailstore.MigrationsHelper
1818
import com.fsck.k9.storage.messages.createFolder
1919
import com.fsck.k9.storage.messages.readFolders
20+
import java.io.IOException
2021
import net.thunderbird.core.android.account.LegacyAccountDto
2122
import net.thunderbird.core.common.mail.Protocols
2223
import net.thunderbird.core.logging.legacy.Log
@@ -220,7 +221,7 @@ class MigrationTo90Test : KoinTest {
220221
}
221222

222223
@Test
223-
fun `given an imap account - when can't fetch imap prefix during the migration - migration should not execute sql queries`() {
224+
fun `given an imap account - when can't fetch imap prefix during the migration due to authentication error - migration should not execute sql queries`() {
224225
// Arrange
225226
populateDatabase()
226227
val prefix = "INBOX."
@@ -256,6 +257,43 @@ class MigrationTo90Test : KoinTest {
256257
}
257258
}
258259

260+
@Test
261+
fun `given an imap account - when can't fetch imap prefix during the migration due to network error - migration should not execute sql queries`() {
262+
// Arrange
263+
populateDatabase()
264+
val prefix = "INBOX."
265+
val imapStore = createImapStoreSpy(
266+
imapPrefix = prefix,
267+
folderPathDelimiter = ".",
268+
ioException = IOException("failed to fetch"),
269+
)
270+
val incomingServerSettings = createIncomingServerSettings()
271+
val account = createAccount(incomingServerSettings)
272+
val migrationHelper = createMigrationsHelper(account)
273+
val dbSpy = spy<SQLiteDatabase> { database }
274+
val migration = MigrationTo90(
275+
db = dbSpy,
276+
migrationsHelper = migrationHelper,
277+
imapStoreFactory = createImapStoreFactory(imapStore),
278+
)
279+
val expected = database.readFolders().map { it.serverId }
280+
val updateQuery = migration.buildQuery(imapPrefix = prefix)
281+
282+
// Act
283+
migration.removeImapPrefixFromFolderServerId()
284+
val actual = database.readFolders().mapNotNull { it.serverId }
285+
testLogger.dumpLogs()
286+
287+
// Assert
288+
verify(imapStore, times(1)).fetchImapPrefix()
289+
verify(dbSpy, times(0)).execSQL(updateQuery)
290+
assertThat(actual)
291+
.all {
292+
hasSize(expected.size)
293+
isEqualTo(expected)
294+
}
295+
}
296+
259297
private fun createIncomingServerSettings(
260298
protocolType: String = Protocols.IMAP,
261299
authType: AuthType = AuthType.NONE,
@@ -308,6 +346,7 @@ class MigrationTo90Test : KoinTest {
308346
imapPrefix: String? = null,
309347
folderPathDelimiter: FolderPathDelimiter = FOLDER_DEFAULT_PATH_DELIMITER,
310348
authenticationFailedException: AuthenticationFailedException? = null,
349+
ioException: IOException? = null,
311350
): ImapStore = spy<ImapStore> {
312351
on { this.combinedPrefix } doReturn imapPrefix
313352
?.takeIf { it.isNotBlank() }
@@ -317,6 +356,9 @@ class MigrationTo90Test : KoinTest {
317356
if (authenticationFailedException != null) {
318357
throw authenticationFailedException
319358
}
359+
if (ioException != null) {
360+
throw ioException
361+
}
320362
}
321363
}
322364

0 commit comments

Comments
 (0)