Merge "Supporting auto migrations in MigrationTestHelper." into androidx-main
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
index 16dc991..9938afa4 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
@@ -16,6 +16,7 @@
 
 package androidx.room.writer
 
+import androidx.annotation.NonNull
 import androidx.room.ext.AndroidTypeNames
 import androidx.room.ext.CommonTypeNames
 import androidx.room.ext.L
@@ -130,7 +131,7 @@
         val scope = CodeGenScope(this)
         return MethodSpec.methodBuilder("getRequiredAutoMigrationSpecs").apply {
             addAnnotation(Override::class.java)
-            addModifiers(PROTECTED)
+            addModifiers(PUBLIC)
             returns(
                 ParameterizedTypeName.get(
                     CommonTypeNames.SET,
@@ -349,13 +350,27 @@
 
     private fun getAutoMigrations(): MethodSpec {
         return MethodSpec.methodBuilder("getAutoMigrations").apply {
-            addModifiers(PROTECTED)
+            addModifiers(PUBLIC)
             addAnnotation(Override::class.java)
+            addParameter(
+                ParameterSpec.builder(
+                    ParameterizedTypeName.get(
+                        CommonTypeNames.MAP,
+                        ParameterizedTypeName.get(
+                            ClassName.get(Class::class.java),
+                            WildcardTypeName.subtypeOf(RoomTypeNames.AUTO_MIGRATION_SPEC)
+                        ),
+                        RoomTypeNames.AUTO_MIGRATION_SPEC
+                    ),
+                    "autoMigrationSpecsMap"
+                ).addAnnotation(NonNull::class.java).build()
+            )
+
             returns(ParameterizedTypeName.get(CommonTypeNames.LIST, RoomTypeNames.MIGRATION))
             val autoMigrationsList = database.autoMigrations.map { autoMigrationResult ->
                 if (autoMigrationResult.isSpecProvided) {
                     CodeBlock.of(
-                        "new $T(mAutoMigrationSpecs.get($T.class))",
+                        "new $T(autoMigrationSpecsMap.get($T.class))",
                         autoMigrationResult.implTypeName,
                         autoMigrationResult.specClassName
                     )
diff --git a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
index 5dd84db..e9df8c9 100644
--- a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
+++ b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
@@ -1,5 +1,6 @@
 package foo.bar;
 
+import androidx.annotation.NonNull;
 import androidx.room.DatabaseConfiguration;
 import androidx.room.InvalidationTracker;
 import androidx.room.RoomOpenHelper;
@@ -188,13 +189,14 @@
     }
 
     @Override
-    protected Set<Class<? extends AutoMigrationSpec>> getRequiredAutoMigrationSpecs() {
+    public Set<Class<? extends AutoMigrationSpec>> getRequiredAutoMigrationSpecs() {
         final HashSet<Class<? extends AutoMigrationSpec>> _autoMigrationSpecsSet = new HashSet<Class<? extends AutoMigrationSpec>>();
         return _autoMigrationSpecsSet;
     }
 
     @Override
-    protected List<Migration> getAutoMigrations() {
+    public List<Migration> getAutoMigrations(
+            @NonNull Map<Class<? extends AutoMigrationSpec>, AutoMigrationSpec> autoMigrationSpecsMap) {
         return Arrays.asList();
     }
 
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt
index faabb9d..8c72847 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt
@@ -17,11 +17,11 @@
 package androidx.room.integration.kotlintestapp.migration
 
 import androidx.room.Room
+import androidx.room.RoomDatabase
 import androidx.room.migration.Migration
 import androidx.room.testing.MigrationTestHelper
 import androidx.room.util.TableInfo
 import androidx.sqlite.db.SupportSQLiteDatabase
-import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
 import androidx.test.filters.MediumTest
 import androidx.test.platform.app.InstrumentationRegistry
 import org.hamcrest.CoreMatchers.`is`
@@ -40,20 +40,21 @@
     @get:Rule
     var helper: MigrationTestHelper = MigrationTestHelper(
         InstrumentationRegistry.getInstrumentation(),
-        MigrationDbKotlin::class.java.canonicalName,
-        FrameworkSQLiteOpenHelperFactory()
+        MigrationDbKotlin::class.java
     )
 
     companion object {
         val TEST_DB = "migration-test"
     }
 
+    abstract class EmptyDb : RoomDatabase()
+
     @Test
     @Throws(IOException::class)
     fun giveBadResource() {
         val helper = MigrationTestHelper(
             InstrumentationRegistry.getInstrumentation(),
-            "foo", FrameworkSQLiteOpenHelperFactory()
+            EmptyDb::class.java
         )
         try {
             helper.createDatabase(TEST_DB, 1)
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java
index fa6fa9d..3206ff9 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java
@@ -16,17 +16,13 @@
 
 package androidx.room.integration.testapp.migration;
 
-import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.fail;
-
-import android.database.sqlite.SQLiteException;
 
 import androidx.annotation.NonNull;
-import androidx.room.Room;
 import androidx.room.migration.Migration;
 import androidx.room.testing.MigrationTestHelper;
+import androidx.room.util.TableInfo;
 import androidx.sqlite.db.SupportSQLiteDatabase;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.LargeTest;
@@ -49,88 +45,42 @@
     public MigrationTestHelper helper;
 
     public AutoMigrationTest() {
-        helper = new MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
-                AutoMigrationDb.class.getCanonicalName());
+        helper = new MigrationTestHelper(
+                InstrumentationRegistry.getInstrumentation(),
+                AutoMigrationDb.class
+        );
     }
 
     // Run this to create the very 1st version of the db.
     public void createFirstVersion() throws IOException {
-        SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 2);
+        SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1);
+        db.execSQL("INSERT INTO Entity1 (id, name) VALUES (1, 'row1')");
         db.close();
     }
 
-    /**
-     * Tests the case where a non existent auto migration is called.
-     */
-    @Test
-    public void testBadAutoMigrationInput() throws IOException {
-        try (SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1)) {
-            db.execSQL("INSERT INTO Entity1 (id, name) VALUES (1, 'row1')");
-            AutoMigrationDb autoMigrationDbV2 = getLatestDb();
-            helper.runMigrationsAndValidate(
-                    TEST_DB,
-                    2,
-                    true,
-                    autoMigrationDbV2.getAutoGeneratedMigration(3, 4)
-            );
-            fail();
-        } catch (IllegalArgumentException ex) {
-            assertThat(
-                    ex.getMessage(),
-                    is("No AutoMigrations between versions 'from = 3', 'to = "
-                    + "4' have been provided. Annotate Database class with @AutoMigration(from = "
-                    + "3, to = 4) to generate this AutoMigration.")
-            );
-        }
-    }
-
     @Test
     public void goFromV1ToV2() throws IOException {
-        try (SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1)) {
-            db.execSQL("INSERT INTO Entity1 (id, name) VALUES (1, 'row1')");
-        }
-        AutoMigrationDb autoMigrationDbV2 = getLatestDb();
-        helper.runMigrationsAndValidate(
+        createFirstVersion();
+        SupportSQLiteDatabase db = helper.runMigrationsAndValidate(
                 TEST_DB,
                 2,
                 true
         );
-        assertThat(autoMigrationDbV2.dao().getAllEntity1s().size(), is(1));
+        final TableInfo info = TableInfo.read(db, AutoMigrationDb.Entity1.TABLE_NAME);
+        assertThat(info.columns.size(), is(3));
     }
 
     /**
      * Verifies that the user defined migration is selected over using an autoMigration.
      */
     @Test
-    public void goFromV1ToV2WithUserDefinedMigration() throws IOException {
-        try (SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1)) {
-            db.execSQL("INSERT INTO Entity1 (id, name) VALUES (1, 'row1')");
-        }
-
-        try {
-            AutoMigrationDb autoMigrationDbV2 = Room.databaseBuilder(
-                    InstrumentationRegistry.getInstrumentation().getTargetContext(),
-                    AutoMigrationDb.class, TEST_DB).addMigrations(MIGRATION_1_2).build();
-            autoMigrationDbV2.getOpenHelper().getWritableDatabase(); // trigger open
-            helper.closeWhenFinished(autoMigrationDbV2);
-
-            helper.runMigrationsAndValidate(
-                    TEST_DB,
-                    2,
-                    true
-            );
-        } catch (SQLiteException exception) {
-            assertThat(exception.getMessage(), containsString("no such table: Entity0"));
-        }
-    }
-
-    private AutoMigrationDb getLatestDb() {
-        AutoMigrationDb db = Room.databaseBuilder(
-                InstrumentationRegistry.getInstrumentation().getTargetContext(),
-                AutoMigrationDb.class, TEST_DB).build();
-        db.getOpenHelper().getWritableDatabase(); // trigger open
-        helper.closeWhenFinished(db);
-        return db;
+    public void testAutoMigrationsNotProcessedBeforeCustomMigrations() throws IOException {
+        helper.runMigrationsAndValidate(
+                TEST_DB,
+                2,
+                true,
+                MIGRATION_1_2
+        );
     }
 
     private static final Migration MIGRATION_1_2 = new Migration(1, 2) {
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/ProvidedAutoMigrationSpecTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/ProvidedAutoMigrationSpecTest.java
index da5c158..6fdb83b 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/ProvidedAutoMigrationSpecTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/ProvidedAutoMigrationSpecTest.java
@@ -27,11 +27,11 @@
 import androidx.room.Entity;
 import androidx.room.PrimaryKey;
 import androidx.room.ProvidedAutoMigrationSpec;
-import androidx.room.Room;
 import androidx.room.RoomDatabase;
 import androidx.room.migration.AutoMigrationSpec;
 import androidx.room.testing.MigrationTestHelper;
 import androidx.sqlite.db.SupportSQLiteDatabase;
+import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.LargeTest;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -41,6 +41,8 @@
 import org.junit.runner.RunWith;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Test custom database migrations.
@@ -53,11 +55,24 @@
             new ProvidedAutoMigrationDb.MyProvidedAutoMigration("Hi");
 
     @Rule
-    public MigrationTestHelper helper;
+    public MigrationTestHelper helperWithoutSpec;
+    public MigrationTestHelper helperWithSpec;
 
     public ProvidedAutoMigrationSpecTest() {
-        helper = new MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
-                ProvidedAutoMigrationDb.class.getCanonicalName());
+        helperWithoutSpec = new MigrationTestHelper(
+                InstrumentationRegistry.getInstrumentation(),
+                ProvidedAutoMigrationDb.class
+        );
+
+        List<AutoMigrationSpec> specs = new ArrayList<>();
+        specs.add(mProvidedSpec);
+
+        helperWithSpec = new MigrationTestHelper(
+                InstrumentationRegistry.getInstrumentation(),
+                ProvidedAutoMigrationDb.class,
+                specs,
+                new FrameworkSQLiteOpenHelperFactory()
+        );
     }
 
     @Database(
@@ -123,15 +138,15 @@
 
     // Run this to create the very 1st version of the db.
     public void createFirstVersion() throws IOException {
-        SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 2);
+        SupportSQLiteDatabase db = helperWithoutSpec.createDatabase(TEST_DB, 1);
+        db.execSQL("INSERT INTO Entity1 (id, name) VALUES (1, 'row1')");
         db.close();
     }
 
     @Test
     public void testOnPostMigrate() throws IOException {
-        SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1);
-        ProvidedAutoMigrationDb autoMigrationDbV2 = getLatestDb();
-        helper.runMigrationsAndValidate(
+        createFirstVersion();
+        helperWithSpec.runMigrationsAndValidate(
                 TEST_DB,
                 2,
                 true
@@ -143,32 +158,24 @@
      * Verifies that the user defined migration is selected over using an autoMigration.
      */
     @Test
-    public void testNoSpecProvidedInConfig() {
+    public void testNoSpecProvidedInConfig() throws IOException {
+        createFirstVersion();
         try {
-            ProvidedAutoMigrationDb autoMigrationDbV2 = Room.databaseBuilder(
-                    InstrumentationRegistry.getInstrumentation().getTargetContext(),
-                    ProvidedAutoMigrationDb.class, TEST_DB).build();
+            helperWithoutSpec.runMigrationsAndValidate(
+                    TEST_DB,
+                    2,
+                    true
+            );
         } catch (IllegalArgumentException exception) {
             assertThat(
                     exception.getMessage(),
                     containsString(
                             "A required auto migration spec (androidx.room.integration.testapp"
                                     + ".migration.ProvidedAutoMigrationSpecTest"
-                                    + ".ProvidedAutoMigrationDb.MyProvidedAutoMigration) is "
-                                    + "missing in the database configuration."
+                                    + ".ProvidedAutoMigrationDb.MyProvidedAutoMigration) has not "
+                                    + "been provided."
                     )
             );
         }
     }
-
-    private ProvidedAutoMigrationDb getLatestDb() {
-        ProvidedAutoMigrationDb db = Room.databaseBuilder(
-                InstrumentationRegistry.getInstrumentation().getTargetContext(),
-                ProvidedAutoMigrationDb.class, TEST_DB)
-                .addAutoMigrationSpec(mProvidedSpec)
-                .build();
-        db.getOpenHelper().getWritableDatabase(); // trigger open
-        helper.closeWhenFinished(db);
-        return db;
-    }
 }
diff --git a/room/runtime/api/current.txt b/room/runtime/api/current.txt
index 50f212f..c6616ad 100644
--- a/room/runtime/api/current.txt
+++ b/room/runtime/api/current.txt
@@ -52,7 +52,6 @@
     method protected abstract androidx.room.InvalidationTracker createInvalidationTracker();
     method protected abstract androidx.sqlite.db.SupportSQLiteOpenHelper createOpenHelper(androidx.room.DatabaseConfiguration!);
     method @Deprecated public void endTransaction();
-    method protected java.util.List<androidx.room.migration.Migration!> getAutoMigrations();
     method public androidx.room.InvalidationTracker getInvalidationTracker();
     method public androidx.sqlite.db.SupportSQLiteOpenHelper getOpenHelper();
     method public java.util.concurrent.Executor getQueryExecutor();
diff --git a/room/runtime/api/public_plus_experimental_current.txt b/room/runtime/api/public_plus_experimental_current.txt
index 758a9f6..bc1f3c0 100644
--- a/room/runtime/api/public_plus_experimental_current.txt
+++ b/room/runtime/api/public_plus_experimental_current.txt
@@ -42,6 +42,7 @@
   public class Room {
     ctor @Deprecated public Room();
     method public static <T extends androidx.room.RoomDatabase> androidx.room.RoomDatabase.Builder<T!> databaseBuilder(android.content.Context, Class<T!>, String);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static <T, C> T getGeneratedImplementation(Class<C!>, String);
     method public static <T extends androidx.room.RoomDatabase> androidx.room.RoomDatabase.Builder<T!> inMemoryDatabaseBuilder(android.content.Context, Class<T!>);
     field public static final String MASTER_TABLE_NAME = "room_master_table";
   }
@@ -55,7 +56,6 @@
     method protected abstract androidx.room.InvalidationTracker createInvalidationTracker();
     method protected abstract androidx.sqlite.db.SupportSQLiteOpenHelper createOpenHelper(androidx.room.DatabaseConfiguration!);
     method @Deprecated public void endTransaction();
-    method protected java.util.List<androidx.room.migration.Migration!> getAutoMigrations();
     method public androidx.room.InvalidationTracker getInvalidationTracker();
     method public androidx.sqlite.db.SupportSQLiteOpenHelper getOpenHelper();
     method public java.util.concurrent.Executor getQueryExecutor();
diff --git a/room/runtime/api/restricted_current.txt b/room/runtime/api/restricted_current.txt
index 14c301a..51e2dac 100644
--- a/room/runtime/api/restricted_current.txt
+++ b/room/runtime/api/restricted_current.txt
@@ -94,7 +94,6 @@
     method protected abstract androidx.room.InvalidationTracker createInvalidationTracker();
     method protected abstract androidx.sqlite.db.SupportSQLiteOpenHelper createOpenHelper(androidx.room.DatabaseConfiguration!);
     method @Deprecated public void endTransaction();
-    method protected java.util.List<androidx.room.migration.Migration!> getAutoMigrations();
     method public androidx.room.InvalidationTracker getInvalidationTracker();
     method public androidx.sqlite.db.SupportSQLiteOpenHelper getOpenHelper();
     method public java.util.concurrent.Executor getQueryExecutor();
diff --git a/room/runtime/src/main/java/androidx/room/Room.java b/room/runtime/src/main/java/androidx/room/Room.java
index 6a570c4..d252099 100644
--- a/room/runtime/src/main/java/androidx/room/Room.java
+++ b/room/runtime/src/main/java/androidx/room/Room.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
 
 /**
  * Utility class for Room.
@@ -75,7 +76,9 @@
 
     @SuppressWarnings({"TypeParameterUnusedInFormals", "ClassNewInstance"})
     @NonNull
-    static <T, C> T getGeneratedImplementation(Class<C> klass, String suffix) {
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public static <T, C> T getGeneratedImplementation(@NonNull Class<C> klass,
+            @NonNull String suffix) {
         final String fullPackage = klass.getPackage().getName();
         String name = klass.getCanonicalName();
         final String postPackageName = fullPackage.isEmpty()
diff --git a/room/runtime/src/main/java/androidx/room/RoomDatabase.java b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
index 0de4563..b6cf417 100644
--- a/room/runtime/src/main/java/androidx/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
@@ -228,7 +228,7 @@
             }
         }
 
-        List<Migration> autoMigrations = getAutoMigrations();
+        List<Migration> autoMigrations = getAutoMigrations(mAutoMigrationSpecs);
         for (Migration autoMigration : autoMigrations) {
             boolean migrationExists = configuration.migrationContainer.getMigrations()
                             .containsKey(autoMigration.startVersion);
@@ -312,43 +312,16 @@
      * Returns a list of {@link Migration} of a database that have been automatically generated.
      *
      * @return A list of migration instances each of which is a generated autoMigration
-     */
-    @NonNull
-    protected List<Migration> getAutoMigrations() {
-        return Collections.emptyList();
-    }
-
-    /**
-     * Returns a {@link Migration} of a database that have been generated using
-     * {@link AutoMigration} with the specific "from" and "to" version pair.
-     * <p>
-     * If a {@link Migration} with the given "from" and "to" versions cannot be found, this
-     * method will throw a {@link IllegalArgumentException}.
-     *
-     * <p>
-     * This API is intended for testing and all auto-migrations are added by default.
-     *
-     * @param from version of the original database schema to migrate from
-     * @param to version of the new database schema to migrate to
-     * @return migration instance of a generated autoMigration
+     * @param autoMigrationSpecs
      *
      * @hide
      */
     @NonNull
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    public Migration getAutoGeneratedMigration(int from, int to) {
-        // TODO: (b/181985265) Support testing automigrations in MigrationTestHelper and remove
-        //  this method
-        List<Migration> autoMigrations = getAutoMigrations();
-        for (Migration autoMigration : autoMigrations) {
-            if (autoMigration.startVersion == from && autoMigration.endVersion == to) {
-                return autoMigration;
-            }
-        }
-        throw new IllegalArgumentException("No AutoMigrations between versions 'from = " + from
-                + "', 'to = " + to + "' have been provided. Annotate Database class with "
-                + "@AutoMigration(from = " + from + ", to = " + to + ") to generate this "
-                + "AutoMigration.");
+    public List<Migration> getAutoMigrations(
+            @NonNull Map<Class<? extends AutoMigrationSpec>, AutoMigrationSpec> autoMigrationSpecs
+    ) {
+        return Collections.emptyList();
     }
 
     /**
@@ -428,7 +401,7 @@
      */
     @NonNull
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    protected Set<Class<? extends AutoMigrationSpec>> getRequiredAutoMigrationSpecs() {
+    public Set<Class<? extends AutoMigrationSpec>> getRequiredAutoMigrationSpecs() {
         return Collections.emptySet();
     }
 
diff --git a/room/testing/api/current.txt b/room/testing/api/current.txt
index 891c1b7..ea0639e 100644
--- a/room/testing/api/current.txt
+++ b/room/testing/api/current.txt
@@ -2,8 +2,11 @@
 package androidx.room.testing {
 
   public class MigrationTestHelper extends org.junit.rules.TestWatcher {
-    ctor public MigrationTestHelper(android.app.Instrumentation!, String!);
-    ctor public MigrationTestHelper(android.app.Instrumentation!, String!, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory!);
+    ctor @Deprecated public MigrationTestHelper(android.app.Instrumentation!, String!);
+    ctor @Deprecated public MigrationTestHelper(android.app.Instrumentation!, String!, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory!);
+    ctor public MigrationTestHelper(android.app.Instrumentation, Class<? extends androidx.room.RoomDatabase>);
+    ctor public MigrationTestHelper(android.app.Instrumentation, Class<? extends androidx.room.RoomDatabase>, java.util.List<androidx.room.migration.AutoMigrationSpec!>);
+    ctor public MigrationTestHelper(android.app.Instrumentation, Class<? extends androidx.room.RoomDatabase>, java.util.List<androidx.room.migration.AutoMigrationSpec!>, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory);
     method public void closeWhenFinished(androidx.sqlite.db.SupportSQLiteDatabase!);
     method public void closeWhenFinished(androidx.room.RoomDatabase!);
     method public androidx.sqlite.db.SupportSQLiteDatabase! createDatabase(String!, int) throws java.io.IOException;
diff --git a/room/testing/api/public_plus_experimental_current.txt b/room/testing/api/public_plus_experimental_current.txt
index 891c1b7..ea0639e 100644
--- a/room/testing/api/public_plus_experimental_current.txt
+++ b/room/testing/api/public_plus_experimental_current.txt
@@ -2,8 +2,11 @@
 package androidx.room.testing {
 
   public class MigrationTestHelper extends org.junit.rules.TestWatcher {
-    ctor public MigrationTestHelper(android.app.Instrumentation!, String!);
-    ctor public MigrationTestHelper(android.app.Instrumentation!, String!, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory!);
+    ctor @Deprecated public MigrationTestHelper(android.app.Instrumentation!, String!);
+    ctor @Deprecated public MigrationTestHelper(android.app.Instrumentation!, String!, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory!);
+    ctor public MigrationTestHelper(android.app.Instrumentation, Class<? extends androidx.room.RoomDatabase>);
+    ctor public MigrationTestHelper(android.app.Instrumentation, Class<? extends androidx.room.RoomDatabase>, java.util.List<androidx.room.migration.AutoMigrationSpec!>);
+    ctor public MigrationTestHelper(android.app.Instrumentation, Class<? extends androidx.room.RoomDatabase>, java.util.List<androidx.room.migration.AutoMigrationSpec!>, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory);
     method public void closeWhenFinished(androidx.sqlite.db.SupportSQLiteDatabase!);
     method public void closeWhenFinished(androidx.room.RoomDatabase!);
     method public androidx.sqlite.db.SupportSQLiteDatabase! createDatabase(String!, int) throws java.io.IOException;
diff --git a/room/testing/api/restricted_current.txt b/room/testing/api/restricted_current.txt
index 891c1b7..ea0639e 100644
--- a/room/testing/api/restricted_current.txt
+++ b/room/testing/api/restricted_current.txt
@@ -2,8 +2,11 @@
 package androidx.room.testing {
 
   public class MigrationTestHelper extends org.junit.rules.TestWatcher {
-    ctor public MigrationTestHelper(android.app.Instrumentation!, String!);
-    ctor public MigrationTestHelper(android.app.Instrumentation!, String!, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory!);
+    ctor @Deprecated public MigrationTestHelper(android.app.Instrumentation!, String!);
+    ctor @Deprecated public MigrationTestHelper(android.app.Instrumentation!, String!, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory!);
+    ctor public MigrationTestHelper(android.app.Instrumentation, Class<? extends androidx.room.RoomDatabase>);
+    ctor public MigrationTestHelper(android.app.Instrumentation, Class<? extends androidx.room.RoomDatabase>, java.util.List<androidx.room.migration.AutoMigrationSpec!>);
+    ctor public MigrationTestHelper(android.app.Instrumentation, Class<? extends androidx.room.RoomDatabase>, java.util.List<androidx.room.migration.AutoMigrationSpec!>, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory);
     method public void closeWhenFinished(androidx.sqlite.db.SupportSQLiteDatabase!);
     method public void closeWhenFinished(androidx.room.RoomDatabase!);
     method public androidx.sqlite.db.SupportSQLiteDatabase! createDatabase(String!, int) throws java.io.IOException;
diff --git a/room/testing/src/main/java/androidx/room/testing/MigrationTestHelper.java b/room/testing/src/main/java/androidx/room/testing/MigrationTestHelper.java
index c846037..02c5192 100644
--- a/room/testing/src/main/java/androidx/room/testing/MigrationTestHelper.java
+++ b/room/testing/src/main/java/androidx/room/testing/MigrationTestHelper.java
@@ -23,12 +23,15 @@
 import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.arch.core.executor.ArchTaskExecutor;
+import androidx.room.AutoMigration;
 import androidx.room.DatabaseConfiguration;
 import androidx.room.Room;
 import androidx.room.RoomDatabase;
 import androidx.room.RoomOpenHelper;
 import androidx.room.RoomOpenHelper.ValidationResult;
+import androidx.room.migration.AutoMigrationSpec;
 import androidx.room.migration.Migration;
 import androidx.room.migration.bundle.DatabaseBundle;
 import androidx.room.migration.bundle.DatabaseViewBundle;
@@ -91,14 +94,27 @@
     private List<WeakReference<RoomDatabase>> mManagedRoomDatabases = new ArrayList<>();
     private boolean mTestStarted;
     private Instrumentation mInstrumentation;
+    @Nullable
+    private List<AutoMigrationSpec> mSpecs;
+    @Nullable
+    private Class<? extends RoomDatabase> mDatabaseClass;
 
     /**
      * Creates a new migration helper. It uses the Instrumentation context to load the schema
      * (falls back to the app resources) and the target context to create the database.
      *
+     * @deprecated Cannot be used to run migration tests involving {@link AutoMigration}.
+     * <p>
+     * To test {@link AutoMigration}, you must use
+     * {@link #MigrationTestHelper(Instrumentation, Class, List, SupportSQLiteOpenHelper.Factory)}
+     * for tests containing a {@link androidx.room.ProvidedAutoMigrationSpec}, or use
+     * {@link #MigrationTestHelper(Instrumentation, Class, List)}
+     * otherwise.
+     *
      * @param instrumentation The instrumentation instance.
      * @param assetsFolder    The asset folder in the assets directory.
      */
+    @Deprecated
     public MigrationTestHelper(Instrumentation instrumentation, String assetsFolder) {
         this(instrumentation, assetsFolder, new FrameworkSQLiteOpenHelperFactory());
     }
@@ -107,18 +123,88 @@
      * Creates a new migration helper. It uses the Instrumentation context to load the schema
      * (falls back to the app resources) and the target context to create the database.
      *
+     * @deprecated Cannot be used to run migration tests involving {@link AutoMigration}.
+     * <p>
+     * To test {@link AutoMigration}, you must use
+     * {@link #MigrationTestHelper(Instrumentation, Class, List, SupportSQLiteOpenHelper.Factory)}
+     * for tests containing a {@link androidx.room.ProvidedAutoMigrationSpec}, or use
+     * {@link #MigrationTestHelper(Instrumentation, Class, List)}
+     * otherwise.
+     *
      * @param instrumentation The instrumentation instance.
      * @param assetsFolder    The asset folder in the assets directory.
      * @param openFactory     Factory class that allows creation of {@link SupportSQLiteOpenHelper}
      */
+    @Deprecated
     public MigrationTestHelper(Instrumentation instrumentation, String assetsFolder,
             SupportSQLiteOpenHelper.Factory openFactory) {
         mInstrumentation = instrumentation;
+        mAssetsFolder = assetsFolder;
+        mOpenFactory = openFactory;
+        mDatabaseClass = null;
+        mSpecs = new ArrayList<>();
+    }
+
+    /**
+     * Creates a new migration helper. It uses the Instrumentation context to load the schema
+     * (falls back to the app resources) and the target context to create the database.
+     *
+     * @param instrumentation The instrumentation instance.
+     * @param databaseClass   The Database class to be tested.
+     */
+    public MigrationTestHelper(@NonNull Instrumentation instrumentation,
+            @NonNull Class<? extends RoomDatabase> databaseClass) {
+        this(instrumentation, databaseClass, new ArrayList<>(),
+                new FrameworkSQLiteOpenHelperFactory());
+    }
+
+    /**
+     * Creates a new migration helper. It uses the Instrumentation context to load the schema
+     * (falls back to the app resources) and the target context to create the database.
+     * <p>
+     * An instance of a class annotated with {@link androidx.room.ProvidedAutoMigrationSpec} has
+     * to be provided to Room using this constructor. MigrationTestHelper will map auto migration
+     * spec classes to their provided instances before running and validatingt the Migrations.
+     *
+     * @param instrumentation The instrumentation instance.
+     * @param databaseClass   The Database class to be tested.
+     * @param specs           The list of available auto migration specs that will be provided to
+     *                        Room at runtime.
+     */
+    public MigrationTestHelper(@NonNull Instrumentation instrumentation,
+            @NonNull Class<? extends RoomDatabase> databaseClass,
+            @NonNull List<AutoMigrationSpec> specs) {
+        this(instrumentation, databaseClass, specs, new FrameworkSQLiteOpenHelperFactory());
+    }
+
+    /**
+     * Creates a new migration helper. It uses the Instrumentation context to load the schema
+     * (falls back to the app resources) and the target context to create the database.
+     * <p>
+     * An instance of a class annotated with {@link androidx.room.ProvidedAutoMigrationSpec} has
+     * to be provided to Room using this constructor. MigrationTestHelper will map auto migration
+     * spec classes to their provided instances before running and validatingt the Migrations.
+     *
+     * @param instrumentation The instrumentation instance.
+     * @param databaseClass   The Database class to be tested.
+     * @param specs           The list of available auto migration specs that will be provided to
+     *                        Room at runtime.
+     * @param openFactory     Factory class that allows creation of {@link SupportSQLiteOpenHelper}
+     */
+    public MigrationTestHelper(@NonNull Instrumentation instrumentation,
+            @NonNull Class<? extends RoomDatabase> databaseClass,
+            @NonNull List<AutoMigrationSpec> specs,
+            @NonNull SupportSQLiteOpenHelper.Factory openFactory
+    ) {
+        String assetsFolder = databaseClass.getCanonicalName();
+        mInstrumentation = instrumentation;
         if (assetsFolder.endsWith("/")) {
             assetsFolder = assetsFolder.substring(0, assetsFolder.length() - 1);
         }
         mAssetsFolder = assetsFolder;
         mOpenFactory = openFactory;
+        mDatabaseClass = databaseClass;
+        mSpecs = specs;
     }
 
     @Override
@@ -144,7 +230,7 @@
         if (dbPath.exists()) {
             Log.d(TAG, "deleting database file " + name);
             if (!dbPath.delete()) {
-                throw new IllegalStateException("there is a database file and i could not delete"
+                throw new IllegalStateException("There is a database file and I could not delete"
                         + " it. Make sure you don't have any open connections to that database"
                         + " before calling this method.");
             }
@@ -214,6 +300,7 @@
         }
         SchemaBundle schemaBundle = loadSchema(version);
         RoomDatabase.MigrationContainer container = new RoomDatabase.MigrationContainer();
+        container.addMigrations(getAutoMigrations(mSpecs));
         container.addMigrations(migrations);
         DatabaseConfiguration configuration = new DatabaseConfiguration(
                 mInstrumentation.getTargetContext(),
@@ -244,6 +331,75 @@
         return openDatabase(name, roomOpenHelper);
     }
 
+    /**
+     * Returns a list of {@link Migration} of a database that has been generated using
+     * {@link AutoMigration}.
+     */
+    @NonNull
+    private List<Migration> getAutoMigrations(List<AutoMigrationSpec> userProvidedSpecs) {
+        if (mDatabaseClass == null) {
+            if (userProvidedSpecs.isEmpty()) {
+                // TODO: Detect that there are auto migrations to test when a deprecated
+                //  constructor is used.
+                Log.e(TAG, "If you have any AutoMigrations in your implementation, you must use "
+                        + "a non-deprecated MigrationTestHelper constructor to provide the "
+                        + "Database class in order to test them. If you do not have any "
+                        + "AutoMigrations to test, you may ignore this warning.");
+                return new ArrayList<>();
+            } else {
+                throw new IllegalStateException("You must provide the database class in the "
+                        + "MigrationTestHelper constructor in order to test auto migrations.");
+            }
+        }
+
+        RoomDatabase db = Room.getGeneratedImplementation(mDatabaseClass, "_Impl");
+        Set<Class<? extends AutoMigrationSpec>> requiredAutoMigrationSpecs =
+                db.getRequiredAutoMigrationSpecs();
+        return db.getAutoMigrations(
+                createAutoMigrationSpecMap(requiredAutoMigrationSpecs, userProvidedSpecs)
+        );
+    }
+
+    /**
+     * Maps auto migration spec classes to their provided instance.
+     */
+    private Map<Class<? extends AutoMigrationSpec>, AutoMigrationSpec> createAutoMigrationSpecMap(
+            Set<Class<? extends AutoMigrationSpec>> requiredAutoMigrationSpecs,
+            List<AutoMigrationSpec> userProvidedSpecs) {
+        Map<Class<? extends AutoMigrationSpec>, AutoMigrationSpec> specMap = new HashMap<>();
+        if (requiredAutoMigrationSpecs.isEmpty()) {
+            return specMap;
+        }
+
+        if (userProvidedSpecs == null) {
+            throw new IllegalStateException(
+                    "You must provide all required auto migration specs in the "
+                            + "MigrationTestHelper constructor."
+            );
+        }
+
+        for (Class<? extends AutoMigrationSpec> spec : requiredAutoMigrationSpecs) {
+            boolean found = false;
+            AutoMigrationSpec match = null;
+            for (AutoMigrationSpec provided : userProvidedSpecs) {
+                if (spec.isAssignableFrom(provided.getClass())) {
+                    found = true;
+                    match = provided;
+                    break;
+                }
+            }
+            if (!found) {
+                throw new IllegalArgumentException(
+                        "A required auto migration spec (" + spec.getCanonicalName() + ") has not"
+                                + " been provided."
+                );
+            }
+            specMap.put(spec, match);
+        }
+        return specMap;
+    }
+
+
     private SupportSQLiteDatabase openDatabase(String name, RoomOpenHelper roomOpenHelper) {
         SupportSQLiteOpenHelper.Configuration config =
                 SupportSQLiteOpenHelper.Configuration
diff --git a/work/workmanager/src/androidTest/java/androidx/work/WorkDatabasePathHelperTest.kt b/work/workmanager/src/androidTest/java/androidx/work/WorkDatabasePathHelperTest.kt
index fc3f164..cd70bd7 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/WorkDatabasePathHelperTest.kt
+++ b/work/workmanager/src/androidTest/java/androidx/work/WorkDatabasePathHelperTest.kt
@@ -37,6 +37,8 @@
 
 @RunWith(AndroidJUnit4::class)
 @LargeTest
+@Suppress("DEPRECATION")
+// TODO: (b/189268580) Update this test to use the new constructors in MigrationTestHelper.
 class WorkDatabasePathHelperTest {
     @get:Rule
     val migrationTestHelper = MigrationTestHelper(