| /* |
| * Copyright 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package androidx.work; |
| |
| import static android.database.sqlite.SQLiteDatabase.CONFLICT_FAIL; |
| |
| import static org.hamcrest.CoreMatchers.is; |
| import static org.hamcrest.MatcherAssert.assertThat; |
| |
| import android.arch.persistence.db.SupportSQLiteDatabase; |
| import android.arch.persistence.db.framework.FrameworkSQLiteOpenHelperFactory; |
| import android.arch.persistence.room.testing.MigrationTestHelper; |
| import android.content.ContentValues; |
| import android.database.Cursor; |
| import android.database.sqlite.SQLiteException; |
| import android.support.test.InstrumentationRegistry; |
| import android.support.test.filters.MediumTest; |
| import android.support.test.runner.AndroidJUnit4; |
| |
| import androidx.work.impl.WorkDatabase; |
| import androidx.work.impl.WorkDatabaseMigrations; |
| import androidx.work.impl.model.WorkSpec; |
| import androidx.work.impl.model.WorkTypeConverters; |
| import androidx.work.worker.TestWorker; |
| |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.UUID; |
| |
| @RunWith(AndroidJUnit4.class) |
| public class WorkDatabaseMigrationTest { |
| |
| private static final String TEST_DATABASE = "workdatabase-test"; |
| private static final boolean VALIDATE_DROPPED_TABLES = true; |
| private static final int OLD_VERSION = 1; |
| private static final int NEW_VERSION = 2; |
| private static final String COLUMN_WORKSPEC_ID = "work_spec_id"; |
| private static final String COLUMN_SYSTEM_ID = "system_id"; |
| private static final String COLUMN_ALARM_ID = "alarm_id"; |
| |
| // Queries |
| private static final String INSERT_ALARM_INFO = "INSERT INTO alarmInfo VALUES (?, ?)"; |
| private static final String INSERT_SYSTEM_ID_INFO = "INSERT INTO SystemIdInfo VALUES (?, ?)"; |
| private static final String CHECK_SYSTEM_ID_INFO = "SELECT * FROM SystemIdInfo"; |
| private static final String CHECK_ALARM_INFO = "SELECT * FROM alarmInfo"; |
| private static final String CHECK_TABLE_NAME = "SELECT * FROM %s"; |
| private static final String TABLE_ALARM_INFO = "alarmInfo"; |
| private static final String TABLE_SYSTEM_ID_INFO = "SystemIdInfo"; |
| private static final String TABLE_WORKSPEC = "WorkSpec"; |
| private static final String TABLE_WORKTAG = "WorkTag"; |
| private static final String TABLE_WORKNAME = "WorkName"; |
| |
| private File mDatabasePath; |
| |
| @Rule |
| public MigrationTestHelper mMigrationTestHelper = new MigrationTestHelper( |
| InstrumentationRegistry.getInstrumentation(), |
| WorkDatabase.class.getCanonicalName(), |
| new FrameworkSQLiteOpenHelperFactory()); |
| |
| @Before |
| public void setUp() { |
| // Delete the database if it exists. |
| mDatabasePath = InstrumentationRegistry.getContext().getDatabasePath(TEST_DATABASE); |
| if (mDatabasePath.exists()) { |
| mDatabasePath.delete(); |
| } |
| } |
| |
| @Test |
| @MediumTest |
| public void testMigrationVersion1To2() throws IOException { |
| SupportSQLiteDatabase database = |
| mMigrationTestHelper.createDatabase(TEST_DATABASE, OLD_VERSION); |
| |
| String workSpecId0 = UUID.randomUUID().toString(); |
| ContentValues contentValues = new ContentValues(); |
| contentValues.put("id", workSpecId0); |
| contentValues.put("state", WorkTypeConverters.StateIds.ENQUEUED); |
| contentValues.put("worker_class_name", TestWorker.class.getName()); |
| contentValues.put("input_merger_class_name", OverwritingInputMerger.class.getName()); |
| contentValues.put("input", Data.toByteArray(Data.EMPTY)); |
| contentValues.put("output", Data.toByteArray(Data.EMPTY)); |
| contentValues.put("initial_delay", 0L); |
| contentValues.put("interval_duration", 0L); |
| contentValues.put("flex_duration", 0L); |
| contentValues.put("required_network_type", false); |
| contentValues.put("requires_charging", false); |
| contentValues.put("requires_device_idle", false); |
| contentValues.put("requires_battery_not_low", false); |
| contentValues.put("requires_storage_not_low", false); |
| contentValues.put("content_uri_triggers", |
| WorkTypeConverters.contentUriTriggersToByteArray(new ContentUriTriggers())); |
| contentValues.put("run_attempt_count", 0); |
| contentValues.put("backoff_policy", |
| WorkTypeConverters.backoffPolicyToInt(BackoffPolicy.EXPONENTIAL)); |
| contentValues.put("backoff_delay_duration", WorkRequest.DEFAULT_BACKOFF_DELAY_MILLIS); |
| contentValues.put("period_start_time", 0L); |
| contentValues.put("minimum_retention_duration", 0L); |
| contentValues.put("schedule_requested_at", WorkSpec.SCHEDULE_NOT_REQUESTED_YET); |
| database.insert("workspec", CONFLICT_FAIL, contentValues); |
| |
| String workSpecId1 = UUID.randomUUID().toString(); |
| String workSpecId2 = UUID.randomUUID().toString(); |
| |
| // insert alarmInfos |
| database.execSQL(INSERT_ALARM_INFO, new Object[]{workSpecId1, 1}); |
| database.execSQL(INSERT_ALARM_INFO, new Object[]{workSpecId2, 2}); |
| |
| database.close(); |
| |
| database = mMigrationTestHelper.runMigrationsAndValidate( |
| TEST_DATABASE, |
| NEW_VERSION, |
| VALIDATE_DROPPED_TABLES, |
| WorkDatabaseMigrations.MIGRATION_1_2); |
| |
| Cursor tagCursor = database.query("SELECT * FROM worktag"); |
| assertThat(tagCursor.getCount(), is(1)); |
| tagCursor.moveToFirst(); |
| assertThat(tagCursor.getString(tagCursor.getColumnIndex("tag")), |
| is(TestWorker.class.getName())); |
| assertThat(tagCursor.getString(tagCursor.getColumnIndex("work_spec_id")), is(workSpecId0)); |
| tagCursor.close(); |
| |
| Cursor cursor = database.query(CHECK_SYSTEM_ID_INFO); |
| assertThat(cursor.getCount(), is(2)); |
| cursor.moveToFirst(); |
| assertThat(cursor.getString(cursor.getColumnIndex(COLUMN_WORKSPEC_ID)), is(workSpecId1)); |
| assertThat(cursor.getInt(cursor.getColumnIndex(COLUMN_SYSTEM_ID)), is(1)); |
| cursor.moveToNext(); |
| assertThat(cursor.getString(cursor.getColumnIndex(COLUMN_WORKSPEC_ID)), is(workSpecId2)); |
| assertThat(cursor.getInt(cursor.getColumnIndex(COLUMN_SYSTEM_ID)), is(2)); |
| cursor.close(); |
| |
| assertThat(checkExists(database, TABLE_ALARM_INFO), is(false)); |
| assertThat(checkExists(database, TABLE_WORKSPEC), is(true)); |
| assertThat(checkExists(database, TABLE_WORKTAG), is(true)); |
| assertThat(checkExists(database, TABLE_WORKNAME), is(true)); |
| database.close(); |
| } |
| |
| @Test |
| @MediumTest |
| public void testMigrationVersion2To1() throws IOException { |
| SupportSQLiteDatabase database = |
| mMigrationTestHelper.createDatabase(TEST_DATABASE, NEW_VERSION); |
| |
| String workSpecId1 = UUID.randomUUID().toString(); |
| String workSpecId2 = UUID.randomUUID().toString(); |
| |
| // insert SystemIdInfo |
| database.execSQL(INSERT_SYSTEM_ID_INFO, new Object[]{workSpecId1, 1}); |
| database.execSQL(INSERT_SYSTEM_ID_INFO, new Object[]{workSpecId2, 2}); |
| |
| database.close(); |
| |
| |
| database = mMigrationTestHelper.runMigrationsAndValidate( |
| TEST_DATABASE, |
| OLD_VERSION, |
| VALIDATE_DROPPED_TABLES, |
| WorkDatabaseMigrations.MIGRATION_2_1); |
| |
| Cursor cursor = database.query(CHECK_ALARM_INFO); |
| assertThat(cursor.getCount(), is(2)); |
| cursor.moveToFirst(); |
| assertThat(cursor.getString(cursor.getColumnIndex(COLUMN_WORKSPEC_ID)), is(workSpecId1)); |
| assertThat(cursor.getInt(cursor.getColumnIndex(COLUMN_ALARM_ID)), is(1)); |
| cursor.moveToNext(); |
| assertThat(cursor.getString(cursor.getColumnIndex(COLUMN_WORKSPEC_ID)), is(workSpecId2)); |
| assertThat(cursor.getInt(cursor.getColumnIndex(COLUMN_ALARM_ID)), is(2)); |
| cursor.close(); |
| |
| assertThat(checkExists(database, TABLE_SYSTEM_ID_INFO), is(false)); |
| assertThat(checkExists(database, TABLE_WORKSPEC), is(true)); |
| assertThat(checkExists(database, TABLE_WORKTAG), is(true)); |
| assertThat(checkExists(database, TABLE_WORKNAME), is(true)); |
| database.close(); |
| } |
| |
| @Test |
| @MediumTest |
| public void testMigrationVersion1To2To1() throws IOException { |
| SupportSQLiteDatabase database = |
| mMigrationTestHelper.createDatabase(TEST_DATABASE, OLD_VERSION); |
| |
| String workSpecId1 = UUID.randomUUID().toString(); |
| String workSpecId2 = UUID.randomUUID().toString(); |
| |
| // insert alarmInfos |
| database.execSQL(INSERT_ALARM_INFO, new Object[]{workSpecId1, 1}); |
| database.execSQL(INSERT_ALARM_INFO, new Object[]{workSpecId2, 2}); |
| |
| database.close(); |
| |
| database = mMigrationTestHelper.runMigrationsAndValidate( |
| TEST_DATABASE, |
| NEW_VERSION, |
| VALIDATE_DROPPED_TABLES, |
| WorkDatabaseMigrations.MIGRATION_1_2); |
| |
| database.close(); |
| |
| database = mMigrationTestHelper.runMigrationsAndValidate( |
| TEST_DATABASE, |
| OLD_VERSION, |
| VALIDATE_DROPPED_TABLES, |
| WorkDatabaseMigrations.MIGRATION_2_1); |
| |
| Cursor cursor = database.query(CHECK_ALARM_INFO); |
| assertThat(cursor.getCount(), is(2)); |
| cursor.moveToFirst(); |
| assertThat(cursor.getString(cursor.getColumnIndex(COLUMN_WORKSPEC_ID)), is(workSpecId1)); |
| assertThat(cursor.getInt(cursor.getColumnIndex(COLUMN_ALARM_ID)), is(1)); |
| cursor.moveToNext(); |
| assertThat(cursor.getString(cursor.getColumnIndex(COLUMN_WORKSPEC_ID)), is(workSpecId2)); |
| assertThat(cursor.getInt(cursor.getColumnIndex(COLUMN_ALARM_ID)), is(2)); |
| cursor.close(); |
| |
| assertThat(checkExists(database, TABLE_SYSTEM_ID_INFO), is(false)); |
| assertThat(checkExists(database, TABLE_WORKSPEC), is(true)); |
| assertThat(checkExists(database, TABLE_WORKTAG), is(true)); |
| assertThat(checkExists(database, TABLE_WORKNAME), is(true)); |
| database.close(); |
| } |
| |
| private boolean checkExists(SupportSQLiteDatabase database, String tableName) { |
| Cursor cursor = null; |
| try { |
| cursor = database.query(String.format(CHECK_TABLE_NAME, tableName)); |
| return true; |
| } catch (SQLiteException ignored) { |
| // Should fail with a SQLiteException (no such table: tableName) |
| return false; |
| } finally { |
| if (cursor != null) { |
| cursor.close(); |
| } |
| } |
| } |
| } |