| Index: chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/MultiInstanceMigrationTest.java
|
| diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/MultiInstanceMigrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/MultiInstanceMigrationTest.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..42e264e13ca98f8868e06d1c2f07cd9ebc570b39
|
| --- /dev/null
|
| +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/MultiInstanceMigrationTest.java
|
| @@ -0,0 +1,280 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package org.chromium.chrome.browser.tabmodel;
|
| +
|
| +import android.content.Context;
|
| +import android.test.InstrumentationTestCase;
|
| +import android.test.suitebuilder.annotation.MediumTest;
|
| +
|
| +import org.chromium.base.ContextUtils;
|
| +import org.chromium.base.test.util.AdvancedMockContext;
|
| +import org.chromium.base.test.util.Feature;
|
| +import org.chromium.chrome.browser.TabState;
|
| +import org.chromium.chrome.test.util.ApplicationData;
|
| +import org.chromium.chrome.test.util.browser.tabmodel.MockTabModelSelector;
|
| +
|
| +import java.io.File;
|
| +import java.io.IOException;
|
| +
|
| +/**
|
| + * Test that migrating the old multi-instance tab state folder structure to the new one works.
|
| + * Previously each instance had its own subdirectory for storing files. Now there is one
|
| + * shared directory.
|
| + */
|
| +public class MultiInstanceMigrationTest extends InstrumentationTestCase {
|
| +
|
| + private Context mAppContext;
|
| +
|
| + @Override
|
| + protected void setUp() throws Exception {
|
| + super.setUp();
|
| + mAppContext = new AdvancedMockContext(
|
| + getInstrumentation().getTargetContext().getApplicationContext());
|
| + ContextUtils.initApplicationContextForTests(mAppContext);
|
| + ApplicationData.clearAppData(mAppContext);
|
| +
|
| + // Set the shared pref stating that the legacy file migration has occurred. The
|
| + // multi-instance migration won't happen if the legacy path is taken.
|
| + ContextUtils.getAppSharedPreferences().edit().putBoolean(
|
| + TabPersistentStore.PREF_HAS_RUN_FILE_MIGRATION, true).apply();
|
| + }
|
| +
|
| + @Override
|
| + protected void tearDown() throws Exception {
|
| + super.tearDown();
|
| + ApplicationData.clearAppData(mAppContext);
|
| + }
|
| +
|
| + /**
|
| + * Tests that normal migration of multi-instance state files works.
|
| + */
|
| + @MediumTest
|
| + @Feature({"TabPersistentStore"})
|
| + public void testMigrateData() throws IOException {
|
| + // Write old state files.
|
| + File[] stateDirs = createOldStateDirs(TabWindowManager.MAX_SIMULTANEOUS_SELECTORS, true);
|
| + File stateFile0 = new File(stateDirs[0], TabPersistentStore.SAVED_STATE_FILE);
|
| + File stateFile1 = new File(stateDirs[1], TabPersistentStore.SAVED_STATE_FILE);
|
| + File stateFile2 = new File(stateDirs[2], TabPersistentStore.SAVED_STATE_FILE);
|
| + File customTabsStateFile = new File(stateDirs[3], TabPersistentStore.SAVED_STATE_FILE);
|
| +
|
| + assertTrue("Could not create state file 0", stateFile0.createNewFile());
|
| + assertTrue("Could not create state file 1", stateFile1.createNewFile());
|
| + assertTrue("Could not create state file 2", stateFile2.createNewFile());
|
| + assertTrue("Could not create custom tabs state file", customTabsStateFile.createNewFile());
|
| +
|
| + // Create a couple of tabs for each tab state subdirectory.
|
| + File tab0 = new File(stateDirs[0], TabState.SAVED_TAB_STATE_FILE_PREFIX + "0");
|
| + File tab1 = new File(stateDirs[0], TabState.SAVED_TAB_STATE_FILE_PREFIX + "1");
|
| + File tab2 = new File(stateDirs[1], TabState.SAVED_TAB_STATE_FILE_PREFIX + "2");
|
| + File tab3 = new File(stateDirs[1], TabState.SAVED_TAB_STATE_FILE_PREFIX_INCOGNITO + "3");
|
| + File tab4 = new File(stateDirs[2], TabState.SAVED_TAB_STATE_FILE_PREFIX + "4");
|
| + File tab5 = new File(stateDirs[2], TabState.SAVED_TAB_STATE_FILE_PREFIX_INCOGNITO + "5");
|
| + File tab6 = new File(stateDirs[3], TabState.SAVED_TAB_STATE_FILE_PREFIX + "6");
|
| +
|
| + assertTrue("Could not create tab 0 file", tab0.createNewFile());
|
| + assertTrue("Could not create tab 1 file", tab1.createNewFile());
|
| + assertTrue("Could not create tab 2 file", tab2.createNewFile());
|
| + assertTrue("Could not create tab 3 file", tab3.createNewFile());
|
| + assertTrue("Could not create tab 4 file", tab4.createNewFile());
|
| + assertTrue("Could not create tab 5 file", tab5.createNewFile());
|
| + assertTrue("Could not create tab 6 file", tab6.createNewFile());
|
| +
|
| + // Build the TabPersistentStore which will try to move the files.
|
| + MockTabModelSelector selector = new MockTabModelSelector(0, 0, null);
|
| + TabPersistentStore store = new TabPersistentStore(selector, 0, mAppContext, null, null);
|
| + store.waitForMigrationToFinish();
|
| +
|
| + // Make sure we don't hit the migration path again.
|
| + assertTrue(ContextUtils.getAppSharedPreferences().getBoolean(
|
| + TabPersistentStore.PREF_HAS_RUN_MULTI_INSTANCE_FILE_MIGRATION, false));
|
| +
|
| + // Check that all metadata files moved.
|
| + File newStateFile0 = new File(stateDirs[0], TabPersistentStore.getStateFileName(0));
|
| + File newStateFile1 = new File(stateDirs[0], TabPersistentStore.getStateFileName(1));
|
| + File newStateFile2 = new File(stateDirs[0], TabPersistentStore.getStateFileName(2));
|
| + File newCustomTabsStateFile = new File(stateDirs[0], TabPersistentStore.getStateFileName(
|
| + TabModelSelectorImpl.CUSTOM_TABS_SELECTOR_INDEX));
|
| + assertTrue("Could not find new state file 0", newStateFile0.exists());
|
| + assertTrue("Could not find new state file 1", newStateFile1.exists());
|
| + assertTrue("Could not find new state file 2", newStateFile2.exists());
|
| + assertTrue("Could not find new custom tabs state file", newCustomTabsStateFile.exists());
|
| + assertFalse("Could still find old state file 0", stateFile0.exists());
|
| + assertFalse("Could still find old state file 1", stateFile1.exists());
|
| + assertFalse("Could still find old state file 2", stateFile2.exists());
|
| + assertFalse("Could still find old custom tabs state file", customTabsStateFile.exists());
|
| +
|
| + // Check that tab 0 and 1 did not move.
|
| + assertTrue("Could not find tab 0 file", tab0.exists());
|
| + assertTrue("Could not find tab 1 file", tab1.exists());
|
| +
|
| + // Check that tabs 2-5 did move.
|
| + File newTab2 = new File(stateDirs[0], TabState.SAVED_TAB_STATE_FILE_PREFIX + "2");
|
| + File newTab3 = new File(stateDirs[0], TabState.SAVED_TAB_STATE_FILE_PREFIX_INCOGNITO + "3");
|
| + File newTab4 = new File(stateDirs[0], TabState.SAVED_TAB_STATE_FILE_PREFIX + "4");
|
| + File newTab5 = new File(stateDirs[0], TabState.SAVED_TAB_STATE_FILE_PREFIX_INCOGNITO + "5");
|
| + assertTrue("Could not find new tab 2 file", newTab2.exists());
|
| + assertTrue("Could not find new tab 3 file", newTab3.exists());
|
| + assertTrue("Could not find new tab 4 file", newTab4.exists());
|
| + assertTrue("Could not find new tab 5 file", newTab5.exists());
|
| + assertFalse("Could still find old tab 2 file", tab2.exists());
|
| + assertFalse("Could still find old tab 3 file", tab3.exists());
|
| + assertFalse("Could still find old tab 4 file", tab4.exists());
|
| + assertFalse("Could still find old tab 5 file", tab5.exists());
|
| +
|
| + // Check that the custom tab (tab 6) was deleted.
|
| + File newTab6 = new File(stateDirs[0], TabState.SAVED_TAB_STATE_FILE_PREFIX + "6");
|
| + assertFalse("Could still find old tab 6 file", tab6.exists());
|
| + assertFalse("Found new tab 6 file. It should have been deleted.", newTab6.exists());
|
| +
|
| + // Check that old directories were deleted.
|
| + assertFalse("Could still find old state dir 1", stateDirs[1].exists());
|
| + assertFalse("Could still find old state dir 2", stateDirs[2].exists());
|
| + assertFalse("Could still find old custom tabs state dir", stateDirs[3].exists());
|
| + }
|
| +
|
| + /**
|
| + * Tests that the state file migration skips unrelated files. Also tests that migration works
|
| + * if the number of tab state subdirectories to migrate is less than
|
| + * {@code TabWindowManager.MAX_SIMULTANEOUS_SELECTORS}
|
| + */
|
| + @MediumTest
|
| + @Feature({"TabPersistentStore"})
|
| + public void testMigrationLeavesOtherFilesAlone() throws IOException {
|
| + // Write old state files and an extra file.
|
| + File[] stateDirs = createOldStateDirs(2, false);
|
| + File stateFile0 = new File(stateDirs[0], TabPersistentStore.SAVED_STATE_FILE);
|
| + File stateFile1 = new File(stateDirs[1], TabPersistentStore.SAVED_STATE_FILE);
|
| + File tab0 = new File(stateDirs[0], TabState.SAVED_TAB_STATE_FILE_PREFIX + "0");
|
| + File tab1 = new File(stateDirs[1], TabState.SAVED_TAB_STATE_FILE_PREFIX + "1");
|
| + File otherFile = new File(stateDirs[1], "other.file");
|
| +
|
| + assertTrue("Could not create state file 0", stateFile0.createNewFile());
|
| + assertTrue("Could not create state file 1", stateFile1.createNewFile());
|
| + assertTrue("Could not create tab 0 file", tab0.createNewFile());
|
| + assertTrue("Could not create tab 1 file", tab1.createNewFile());
|
| + assertTrue("Could not create other file", otherFile.createNewFile());
|
| +
|
| + // Build the TabPersistentStore which will try to move the files.
|
| + MockTabModelSelector selector = new MockTabModelSelector(0, 0, null);
|
| + TabPersistentStore store = new TabPersistentStore(selector, 0, mAppContext, null, null);
|
| + store.waitForMigrationToFinish();
|
| +
|
| + // Check that the other file wasn't moved.
|
| + File newOtherFile = new File(stateDirs[0], "other.file");
|
| + assertFalse("Could find new other file", newOtherFile.exists());
|
| + assertTrue("Could not find original other file", otherFile.exists());
|
| +
|
| + // Check that the metadata files were renamed and/or moved.
|
| + File newStateFile0 = new File(stateDirs[0], TabPersistentStore.getStateFileName(0));
|
| + File newStateFile1 = new File(stateDirs[0], TabPersistentStore.getStateFileName(1));
|
| + assertTrue("Could not find new state file 0", newStateFile0.exists());
|
| + assertTrue("Could not find new state file 1", newStateFile1.exists());
|
| + assertFalse("Could still find old state file 0", stateFile0.exists());
|
| + assertFalse("Could still find old state file 1", stateFile1.exists());
|
| +
|
| + // Check that tab 0 did not move.
|
| + assertTrue("Could not find tab 0 file", tab0.exists());
|
| +
|
| + // Check that tab 1 did move.
|
| + File newTab1 = new File(stateDirs[0], TabState.SAVED_TAB_STATE_FILE_PREFIX + "1");
|
| + assertTrue("Could not find tab 1 file", newTab1.exists());
|
| + assertFalse("Could still find old tab 1 file", tab1.exists());
|
| + }
|
| +
|
| + /**
|
| + * Tests that migration of multi-instance state files works when tab files with the same name
|
| + * exists in both directories.
|
| + */
|
| + @MediumTest
|
| + @Feature({"TabPersistentStore"})
|
| + public void testMigrateDataDuplicateTabFiles() throws IOException {
|
| + // Write old state files.
|
| + File[] stateDirs = createOldStateDirs(2, false);
|
| + File stateFile0 = new File(stateDirs[0], TabPersistentStore.SAVED_STATE_FILE);
|
| + File stateFile1 = new File(stateDirs[1], TabPersistentStore.SAVED_STATE_FILE);
|
| +
|
| + assertTrue("Could not create state file 0", stateFile0.createNewFile());
|
| + assertTrue("Could not create state file 1", stateFile1.createNewFile());
|
| +
|
| + // Create duplicate "tab0" files and ensure tab0Dir1 has been modified more recently so that
|
| + // it overwrites tab0Dir0.
|
| + File tab0Dir0 = new File(stateDirs[0], TabState.SAVED_TAB_STATE_FILE_PREFIX + "0");
|
| + File tab0Dir1 = new File(stateDirs[1], TabState.SAVED_TAB_STATE_FILE_PREFIX + "0");
|
| + assertTrue("Could not create tab 0-0 file", tab0Dir0.createNewFile());
|
| + assertTrue("Could not create tab 0-1 file", tab0Dir1.createNewFile());
|
| + long expectedTab0LastModifiedTime = tab0Dir0.lastModified() + 1000;
|
| + if (!tab0Dir1.setLastModified(expectedTab0LastModifiedTime)) {
|
| + fail("Failed to set last modified time.");
|
| + }
|
| +
|
| + // Create duplicate "tab1" files and ensure tab1Dir0 has been modified more recently so that
|
| + // it does not get overwritten.
|
| + File tab1Dir0 = new File(stateDirs[0], TabState.SAVED_TAB_STATE_FILE_PREFIX + "1");
|
| + File tab1Dir1 = new File(stateDirs[1], TabState.SAVED_TAB_STATE_FILE_PREFIX + "1");
|
| + assertTrue("Could not create tab 1-0 file", tab1Dir0.createNewFile());
|
| + assertTrue("Could not create tab 1-1 file", tab1Dir1.createNewFile());
|
| + long expectedTab1LastModifiedTime = tab1Dir1.lastModified() + 1000;
|
| + if (!tab1Dir0.setLastModified(expectedTab1LastModifiedTime)) {
|
| + fail("Failed to set last modified time.");
|
| + }
|
| +
|
| + // Build the TabPersistentStore which will try to move the files.
|
| + MockTabModelSelector selector = new MockTabModelSelector(0, 0, null);
|
| + TabPersistentStore store = new TabPersistentStore(selector, 0, mAppContext, null, null);
|
| + store.waitForMigrationToFinish();
|
| +
|
| + // Check that "tab0" still exists and has the expected last modified time.
|
| + assertTrue("Could not find tab 0 file", tab0Dir0.exists());
|
| + assertFalse("Could still find old tab 0 file", tab0Dir1.exists());
|
| + assertEquals("tab 0 file not overwritten properly",
|
| + expectedTab0LastModifiedTime,
|
| + tab0Dir0.lastModified());
|
| +
|
| + // Check that "tab1" still exists and has the expected last modified time.
|
| + assertTrue("Could not find tab 1 file", tab1Dir0.exists());
|
| + assertFalse("Could still find old tab 1 file", tab1Dir1.exists());
|
| + assertEquals("tab 1 file unexpectedly overwritten",
|
| + expectedTab1LastModifiedTime,
|
| + tab1Dir0.lastModified());
|
| +
|
| + // Check that old directory was deleted.
|
| + assertFalse("Could still find old state dir 1", stateDirs[1].exists());
|
| + }
|
| +
|
| + /**
|
| + * Creates tab state directories using the old pre-multi-instance migration file paths where
|
| + * each tab model had its own state directory.
|
| + *
|
| + * @param numRegularDirsToCreate The number of regular tab state directories to create.
|
| + * @param createCustomTabsDir Whether a custom tabs directory should be created.
|
| + * @return An array containing the tab state directories. If createCustomTabsDir is true,
|
| + * a directory for custom tabs will be added to the end of the array.
|
| + */
|
| + private File[] createOldStateDirs(int numRegularDirsToCreate, boolean createCustomTabsDir) {
|
| + int numDirsToCreate =
|
| + createCustomTabsDir ? numRegularDirsToCreate + 1 : numRegularDirsToCreate;
|
| + File[] stateDirs = new File[numDirsToCreate];
|
| + for (int i = 0; i < numRegularDirsToCreate; i++) {
|
| + stateDirs[i] = new File(TabPersistentStore.getOrCreateBaseStateDirectory(),
|
| + Integer.toString(i));
|
| + if (!stateDirs[i].exists()) {
|
| + assertTrue("Could not create state dir " + i, stateDirs[i].mkdir());
|
| + }
|
| + }
|
| +
|
| + if (createCustomTabsDir) {
|
| + stateDirs[numDirsToCreate - 1] = new File(
|
| + TabPersistentStore.getOrCreateBaseStateDirectory(),
|
| + Integer.toString(TabModelSelectorImpl.CUSTOM_TABS_SELECTOR_INDEX));
|
| + if (!stateDirs[numDirsToCreate - 1].exists()) {
|
| + assertTrue("Could not create custom tab state dir",
|
| + stateDirs[numDirsToCreate - 1].mkdir());
|
| + }
|
| + }
|
| +
|
| + return stateDirs;
|
| + }
|
| +}
|
|
|