Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f8a1ab7 authored by Pinyao Ting's avatar Pinyao Ting
Browse files

include reboelctric test for restore

Bug: 141472083
Change-Id: Ibee123b01c74316d493d3aa229acf4a4f815f60b
parent 09b03c55
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
    mockito-robolectric-prebuilt \
    truth-prebuilt
LOCAL_JAVA_LIBRARIES := \
    platform-robolectric-4.3-prebuilt
    platform-robolectric-4.3.1-prebuilt

LOCAL_JAVA_RESOURCE_DIRS := resources config

@@ -56,4 +56,4 @@ LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))../src

LOCAL_ROBOTEST_TIMEOUT := 36000

include prebuilts/misc/common/robolectric/4.3/run_robotests.mk
include prebuilts/misc/common/robolectric/4.3.1/run_robotests.mk
+1 −1
Original line number Diff line number Diff line
sdk=28
sdk=29
+124 −0
Original line number Diff line number Diff line
@@ -16,14 +16,32 @@

package com.android.launcher3.model;

import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE;

import static com.android.launcher3.LauncherSettings.Favorites.BACKUP_TABLE_NAME;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
import static com.android.launcher3.util.LauncherModelHelper.APP_ICON;
import static com.android.launcher3.util.LauncherModelHelper.NO__ICON;
import static com.android.launcher3.util.LauncherModelHelper.SHORTCUT;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.robolectric.util.ReflectionHelpers.setField;

import android.app.backup.BackupManager;
import android.content.pm.PackageInstaller;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.UserHandle;
import android.os.UserManager;

import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.shadows.LShadowBackupManager;
import com.android.launcher3.shadows.LShadowUserManager;
import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.LauncherRoboTestRunner;

@@ -32,6 +50,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.LooperMode;
import org.robolectric.shadow.api.Shadow;

/**
 * Tests to verify backup and restore flow.
@@ -40,18 +59,123 @@ import org.robolectric.annotation.LooperMode;
@LooperMode(LooperMode.Mode.PAUSED)
public class BackupRestoreTest {

    private static final long MY_OLD_PROFILE_ID = 1;
    private static final long MY_PROFILE_ID = 0;
    private static final long OLD_WORK_PROFILE_ID = 11;
    private static final int WORK_PROFILE_ID = 10;

    private static final int SYSTEM_USER = 0;
    private static final int FLAG_SYSTEM = 0x00000800;
    private static final int FLAG_PROFILE = 0x00001000;

    private LShadowUserManager mUserManager;
    private BackupManager mBackupManager;
    private LauncherModelHelper mModelHelper;
    private SQLiteDatabase mDb;
    private InvariantDeviceProfile mIdp;
    private UserHandle mMainProfileUser;
    private UserHandle mWorkProfileUser;

    @Before
    public void setUp() {
        setupUserManager();
        setupBackupManager();
        mModelHelper = new LauncherModelHelper();
        RestoreDbTask.setPending(RuntimeEnvironment.application, true);
        mDb = mModelHelper.provider.getDb();
        mIdp = InvariantDeviceProfile.INSTANCE.get(RuntimeEnvironment.application);
    }

    private void setupUserManager() {
        final UserManager userManager = RuntimeEnvironment.application.getSystemService(
                UserManager.class);
        mUserManager = Shadow.extract(userManager);
        // sign in to primary user
        mMainProfileUser = mUserManager.addUser(SYSTEM_USER, "me", FLAG_SYSTEM);
        // sign in to work profile
        mWorkProfileUser = mUserManager.addUser(WORK_PROFILE_ID, "work", FLAG_PROFILE);
    }

    private void setupBackupManager() {
        mBackupManager = new BackupManager(RuntimeEnvironment.application);
        final LShadowBackupManager bm = Shadow.extract(mBackupManager);
        bm.addProfile(MY_OLD_PROFILE_ID, mMainProfileUser);
        bm.addProfile(OLD_WORK_PROFILE_ID, mWorkProfileUser);
    }

    @Test
    public void testOnCreateDbIfNotExists_CreatesBackup() {
        assertTrue(tableExists(mDb, BACKUP_TABLE_NAME));
    }

    @Test
    public void testOnRestoreSessionWithValidCondition_PerformsRestore() throws Exception {
        setupBackup();
        verifyTableIsFilled(BACKUP_TABLE_NAME, false);
        verifyTableIsEmpty(TABLE_NAME);
        createRestoreSession();
        verifyTableIsFilled(TABLE_NAME, true);
    }

    private void setupBackup() {
        createTableUsingOldProfileId();
        // setup grid for main user on first screen
        mModelHelper.createGrid(new int[][][]{{
                { APP_ICON, APP_ICON, SHORTCUT, SHORTCUT},
                { SHORTCUT, SHORTCUT, NO__ICON, NO__ICON},
                { NO__ICON, NO__ICON, SHORTCUT, SHORTCUT},
                { APP_ICON, SHORTCUT, SHORTCUT, APP_ICON},
            }}, 1, MY_OLD_PROFILE_ID);
        // setup grid for work profile on second screen
        mModelHelper.createGrid(new int[][][]{{
                { NO__ICON, APP_ICON, SHORTCUT, SHORTCUT},
                { SHORTCUT, SHORTCUT, NO__ICON, NO__ICON},
                { NO__ICON, NO__ICON, SHORTCUT, SHORTCUT},
                { APP_ICON, SHORTCUT, SHORTCUT, NO__ICON},
            }}, 2, OLD_WORK_PROFILE_ID);
        // simulates the creation of backup upon restore
        new GridBackupTable(RuntimeEnvironment.application, mDb, mIdp.numHotseatIcons,
                mIdp.numColumns, mIdp.numRows).doBackup(
                        MY_OLD_PROFILE_ID, GridBackupTable.OPTION_REQUIRES_SANITIZATION);
        // reset favorites table
        createTableUsingOldProfileId();
    }

    private void verifyTableIsEmpty(String tableName) {
        assertEquals(0, getCount(mDb, "SELECT * FROM " + tableName));
    }

    private void verifyTableIsFilled(String tableName, boolean sanitized) {
        assertEquals(sanitized ? 12 : 13, getCount(mDb,
                "SELECT * FROM " + tableName + " WHERE profileId = "
                        + (sanitized ? MY_PROFILE_ID : MY_OLD_PROFILE_ID)));
        assertEquals(10, getCount(mDb, "SELECT * FROM " + tableName + " WHERE profileId = "
                + (sanitized ? WORK_PROFILE_ID : OLD_WORK_PROFILE_ID)));
    }

    private void createTableUsingOldProfileId() {
        // simulates the creation of favorites table on old device
        dropTable(mDb, TABLE_NAME);
        addTableToDb(mDb, MY_OLD_PROFILE_ID, false);
    }

    private void createRestoreSession() throws Exception {
        final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
        final PackageInstaller installer = RuntimeEnvironment.application.getPackageManager()
                .getPackageInstaller();
        final int sessionId = installer.createSession(params);
        final PackageInstaller.SessionInfo info = installer.getSessionInfo(sessionId);
        setField(info, "installReason", INSTALL_REASON_DEVICE_RESTORE);
        // TODO: (b/148410677) we should verify the following call instead
        //  InstallSessionHelper.INSTANCE.get(getContext()).restoreDbIfApplicable(info);
        RestoreDbTask.restoreIfPossible(RuntimeEnvironment.application,
                mModelHelper.provider.getHelper(), mBackupManager);
    }

    private static int getCount(SQLiteDatabase db, String sql) {
        try (Cursor c = db.rawQuery(sql, null)) {
            return c.getCount();
        }
    }
}
+45 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 com.android.launcher3.shadows;

import android.app.backup.BackupManager;
import android.os.UserHandle;
import android.util.LongSparseArray;

import androidx.annotation.Nullable;

import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowBackupManager;

/**
 * Extension of {@link ShadowBackupManager} with missing shadow methods
 */
@Implements(value = BackupManager.class)
public class LShadowBackupManager extends ShadowBackupManager {

    private LongSparseArray<UserHandle> mProfileMapping = new LongSparseArray<>();

    public void addProfile(long userSerial, UserHandle userHandle) {
        mProfileMapping.put(userSerial, userHandle);
    }

    @Implementation
    @Nullable
    public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
        return mProfileMapping.get(ancestralSerialNumber);
    }
}
+13 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
@@ -43,6 +44,7 @@ import org.robolectric.shadows.ShadowLauncherApps;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

/**
@@ -111,6 +113,17 @@ public class LShadowLauncherApps extends ShadowLauncherApps {
        return true;
    }

    @Implementation
    public List<PackageInstaller.SessionInfo> getAllPackageInstallerSessions() {
        return RuntimeEnvironment.application.getPackageManager().getPackageInstaller()
                .getAllSessions();
    }

    @Implementation
    public void registerPackageInstallerSessionCallback(
            Executor executor, PackageInstaller.SessionCallback callback) {
    }

    @Override
    protected List<LauncherActivityInfo> getShortcutConfigActivityList(String packageName,
            UserHandle user) {
Loading