Ошибка проверки хэша личности при тестировании миграции комнаты

Я пишу тест, следуя этим инструкциям. В моем тестовом классе есть это правило:

@Rule
public MigrationTestHelper testHelper = new MigrationTestHelper(
        InstrumentationRegistry.getInstrumentation(),
        AppDatabase.class.getCanonicalName(),
        new FrameworkSQLiteOpenHelperFactory()
);

и мой тест выглядит следующим образом:

@Test
public void testMigration9_10() throws IOException {
    // Create the database with version 9
    SupportSQLiteDatabase db = testHelper.createDatabase(TEST_DB_NAME, 9);

    // Insert before migration
    ContentValues values = new ContentValues();
    values.put("rowid", 1);
    ...
    db.insert("foo", SQLiteDatabase.CONFLICT_FAIL, values);

    // Check inserted data
    Cursor c = db.query("SELECT * FROM foo WHERE rowid = " + values.get("rowid"));
    Assert.assertTrue(c.moveToFirst());
    Assert.assertEquals(c.getString(c.getColumnIndex("rowid")), values.get("rowid"));

    // Migrate
    db = testHelper.runMigrationsAndValidate(TEST_DB_NAME, 10, true, DatabaseCreator.MIGRATION
at android.arch.persistence.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:119)
at android.arch.persistence.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:100)
at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen(FrameworkSQLiteOpenHelper.java:133)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:282)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:175)
at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:93)
at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:54)
at android.arch.persistence.room.testing.MigrationTestHelper.openDatabase(MigrationTestHelper.java:203)
at android.arch.persistence.room.testing.MigrationTestHelper.runMigrationsAndValidate(MigrationTestHelper.java:193)
10); ... }

Но это терпит неудачу в последней строке (предыдущие утверждения прошли хорошо), говоря следующее:

java.lang.IllegalStateException: Комната не может проверить целостность данных. Похоже, вы изменили схему, но забыли обновить номер версии. Вы можете просто исправить это, увеличив номер версии.

Что неправильно. Я проследил, что происходит:

  • создать базу данных с идентификационным хэшем версии 9
  • вставить данные
  • проверить данные
  • call runMigrationsAndValidate, which:
    • opens the database
    • проверяет хэш идентификации на версию 10 и терпит неудачу

При проверке хэша идентификации он делает:

private void checkIdentity(SupportSQLiteDatabase db) {
    createMasterTableIfNotExists(db);
    String identityHash = "";
    Cursor cursor = db.query(new SimpleSQLiteQuery(RoomMasterTable.READ_QUERY));
    //noinspection TryFinallyCanBeTryWithResources
    try {
        if (cursor.moveToFirst()) {
            identityHash = cursor.getString(0);
        }
    } finally {
        cursor.close();
    }
    if (!mIdentityHash.equals(identityHash)) {
        throw new IllegalStateException("Room cannot verify the data integrity. Looks like"
                + " you've changed schema but forgot to update the version number. You can"
                + " simply fix this by increasing the version number.");
    }
}

Таким образом, загруженный identityHash - это тот, который загружен из БД версии 9; а mIdentityHash загружается непосредственно runMigrationsAndValidate с использованием параметра версии, равного 10.

Так что конечно не получается.

Мне интересно, почему он проверяет хэши идентификаторов ДО выполнения миграции.

Вот миграция, даже если я думаю, что она здесь не актуальна:

public static final Migration MIGRATION
at android.arch.persistence.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:119)
at android.arch.persistence.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:100)
at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen(FrameworkSQLiteOpenHelper.java:133)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:282)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:175)
at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:93)
at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:54)
at android.arch.persistence.room.testing.MigrationTestHelper.openDatabase(MigrationTestHelper.java:203)
at android.arch.persistence.room.testing.MigrationTestHelper.runMigrationsAndValidate(MigrationTestHelper.java:193)
10 = new Migration(9, 10) { @Override public void migrate(@NonNull SupportSQLiteDatabase database) { database.beginTransaction(); database.execSQL("ALTER TABLE DeclarationEntity ADD latitude REAL NOT NULL DEFAULT 0.0"); database.execSQL("ALTER TABLE DeclarationEntity ADD longitude REAL NOT NULL DEFAULT 0.0"); database.endTransaction(); } };

Я сделал что-то не так?

PS: вот полная трассировка стека, если это интересно:

at android.arch.persistence.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:119)
at android.arch.persistence.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:100)
at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen(FrameworkSQLiteOpenHelper.java:133)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:282)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:175)
at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:93)
at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:54)
at android.arch.persistence.room.testing.MigrationTestHelper.openDatabase(MigrationTestHelper.java:203)
at android.arch.persistence.room.testing.MigrationTestHelper.runMigrationsAndValidate(MigrationTestHelper.java:193)

Я использую (versions.arch равно 1.0.0):

implementation "android.arch.persistence.room:runtime:${versions.arch}"
annotationProcessor "android.arch.persistence.room:compiler:${versions.arch}"
androidTestImplementation "android.arch.persistence.room:testing:${versions.arch}"

person Benoit Duffez    schedule 31.01.2018    source источник


Ответы (1)


Ну что ж. Оказывается я тупой.

public static final Migration MIGRATION_9_10 = new Migration(9, 10) {
    @Override
    public void migrate(@NonNull SupportSQLiteDatabase database) {
        database.beginTransaction();
        database.execSQL("ALTER TABLE DeclarationEntity ADD latitude REAL NOT NULL DEFAULT 0.0");
        database.execSQL("ALTER TABLE DeclarationEntity ADD longitude REAL NOT NULL DEFAULT 0.0");
        database.setTransactionSuccessful(); // <--- TA-DAAAH
        database.endTransaction();
    }
};

Платформа выполнила обновление, но откатила его.

person Benoit Duffez    schedule 31.01.2018
comment
Кроме того, это бесполезно: фреймворк запускает транзакцию до вызова migrate(), так что это просто бесполезно. - person Benoit Duffez; 09.07.2018