diff --git a/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt b/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt index 659331bd..6e637898 100644 --- a/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt +++ b/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt @@ -299,6 +299,50 @@ class UpgradeDatabaseTest { } } + @Test + fun recoverUpgrade6to7DueToSQLiteExceptionThrown() { + Upgrade0To1().applyTo(db, 0) + Upgrade1To2().applyTo(db, 1) + Upgrade2To3(context).applyTo(db, 2) + Upgrade3To4().applyTo(db, 3) + Upgrade4To5().applyTo(db, 4) + Upgrade5To6().applyTo(db, 5) + + val licenseToken = "licenseToken" + + Sql.update("UPDATE_CHECK_ENTITY") + .set("LICENSE_TOKEN", Sql.toString(licenseToken)) + .set("RELEASE_NOTE", Sql.toString("releaseNote")) + .set("VERSION", Sql.toString("version")) + .set("URL_TO_APK", Sql.toString("urlApk")) + .set("URL_TO_RELEASE_NOTE", Sql.toString("urlReleaseNote")) + .executeOn(db) + + Sql.alterTable("UPDATE_CHECK_ENTITY").renameTo("UPDATE_CHECK_ENTITY_OLD").executeOn(db) + + Sql.createTable("UPDATE_CHECK_ENTITY") // + .id() // + .optionalText("LICENSE_TOKEN") // + .optionalText("RELEASE_NOTE") // + .optionalText("VERSION") // + .optionalText("URL_TO_APK") // + .optionalText("APK_SHA256") // + .optionalText("URL_TO_RELEASE_NOTE") // + .executeOn(db) + + Upgrade6To7().tryToRecoverFromSQLiteException(db) + + Sql.query("UPDATE_CHECK_ENTITY").executeOn(db).use { + it.moveToFirst() + Assert.assertThat(it.getString(it.getColumnIndex("LICENSE_TOKEN")), CoreMatchers.`is`(licenseToken)) + Assert.assertThat(it.getString(it.getColumnIndex("RELEASE_NOTE")), CoreMatchers.nullValue()) + Assert.assertThat(it.getString(it.getColumnIndex("VERSION")), CoreMatchers.nullValue()) + Assert.assertThat(it.getString(it.getColumnIndex("URL_TO_APK")), CoreMatchers.nullValue()) + Assert.assertThat(it.getString(it.getColumnIndex("APK_SHA256")), CoreMatchers.nullValue()) + Assert.assertThat(it.getString(it.getColumnIndex("URL_TO_RELEASE_NOTE")), CoreMatchers.nullValue()) + } + } + @Test fun upgrade7To8() { Upgrade0To1().applyTo(db, 0) diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade6To7.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade6To7.kt index 56d723af..8e625516 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade6To7.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade6To7.kt @@ -1,8 +1,10 @@ package org.cryptomator.data.db +import android.database.sqlite.SQLiteException import org.greenrobot.greendao.database.Database import javax.inject.Inject import javax.inject.Singleton +import timber.log.Timber @Singleton internal class Upgrade6To7 @Inject constructor() : DatabaseUpgrade(6, 7) { @@ -30,12 +32,41 @@ internal class Upgrade6To7 @Inject constructor() : DatabaseUpgrade(6, 7) { .optionalText("URL_TO_RELEASE_NOTE") // .executeOn(db) - Sql.insertInto("UPDATE_CHECK_ENTITY") // - .select("_id", "LICENSE_TOKEN", "RELEASE_NOTE", "VERSION", "URL_TO_APK", "URL_TO_RELEASE_NOTE") // - .columns("_id", "LICENSE_TOKEN", "RELEASE_NOTE", "VERSION", "URL_TO_APK", "URL_TO_RELEASE_NOTE") // - .from("UPDATE_CHECK_ENTITY_OLD") // - .executeOn(db) + try { + Sql.insertInto("UPDATE_CHECK_ENTITY") // + .select("_id", "LICENSE_TOKEN", "RELEASE_NOTE", "VERSION", "URL_TO_APK", "URL_TO_RELEASE_NOTE") // + .columns("_id", "LICENSE_TOKEN", "RELEASE_NOTE", "VERSION", "URL_TO_APK", "URL_TO_RELEASE_NOTE") // + .from("UPDATE_CHECK_ENTITY_OLD") // + .executeOn(db) + } catch (e: SQLiteException) { + Timber.tag("Upgrade6To7").e(e, "Failed to recover data from old update check entity, insert new initial entry. More details in #336") + tryToRecoverFromSQLiteException(db) + } Sql.dropTable("UPDATE_CHECK_ENTITY_OLD").executeOn(db) } + + fun tryToRecoverFromSQLiteException(db: Database) { + var licenseToken: String? = null + + try { + Sql.query("UPDATE_CHECK_ENTITY_OLD").executeOn(db).use { + if (it.moveToNext()) { + licenseToken = it.getString(it.getColumnIndex("LICENSE_TOKEN")) + } + } + } catch (e: SQLiteException) { + Timber.tag("Upgrade6To7").e(e, "Failed to recover license token while recovery, clear license token if used.") + } + + Sql.insertInto("UPDATE_CHECK_ENTITY") // + .integer("_id", 1) // + .text("LICENSE_TOKEN", licenseToken) // + .text("RELEASE_NOTE", null) // + .text("VERSION", null) // + .text("URL_TO_APK", null) // + .text("APK_SHA256", null) // + .text("URL_TO_RELEASE_NOTE", null) // + .executeOn(db) + } }