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

Commit 8553d277 authored by Bernardo Rufino's avatar Bernardo Rufino
Browse files

Add tests for ActiveRestoreSession

Added first set around getAvailableRestoreSets() plus some tidy-up
around setup and unused stubs.

Test: m -j RunFrameworksServicesRoboTests
Change-Id: I9b3bf548251f1262907de96407184bd1822b3429
parent 142f5717
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.backup;

import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThread;
import static com.android.server.backup.testing.TransportData.backupTransport;
import static com.android.server.backup.testing.TransportData.d2dTransport;
import static com.android.server.backup.testing.TransportData.localTransport;
@@ -41,9 +42,9 @@ import android.content.Intent;
import android.os.HandlerThread;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import com.android.server.backup.PackageManagerBackupAgent;
import com.android.server.backup.testing.ShadowAppBackupUtils;
import com.android.server.backup.testing.ShadowBackupPolicyEnforcer;

import com.android.server.testing.shadows.ShadowAppBackupUtils;
import com.android.server.testing.shadows.ShadowBackupPolicyEnforcer;
import com.android.server.backup.testing.TransportData;
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
import com.android.server.backup.transport.TransportNotRegisteredException;
@@ -97,10 +98,7 @@ public class BackupManagerServiceTest {
        mTransport = backupTransport();
        mTransportName = mTransport.transportName;

        mBackupThread = new HandlerThread("backup-test");
        mBackupThread.setUncaughtExceptionHandler(
                (t, e) -> ShadowLog.e(TAG, "Uncaught exception in test thread " + t.getName(), e));
        mBackupThread.start();
        mBackupThread = startBackupThread(this::uncaughtException);
        mShadowBackupLooper = shadowOf(mBackupThread.getLooper());

        ContextWrapper context = RuntimeEnvironment.application;
@@ -121,6 +119,13 @@ public class BackupManagerServiceTest {
        ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(null);
    }

    private void uncaughtException(Thread thread, Throwable e) {
        // Unrelated exceptions are thrown in the backup thread. Until we mock everything properly
        // we should not fail tests because of this. This is not flakiness, the exceptions thrown
        // don't interfere with the tests.
        ShadowLog.e(TAG, "Uncaught exception in test thread " + thread.getName(), e);
    }

    /* Tests for destination string */

    @Test
+28 −24
Original line number Diff line number Diff line
@@ -16,11 +16,13 @@

package com.android.server.backup;

import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBackupManagerServiceBasics;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThreadAndGetLooper;
import static com.android.server.backup.testing.TransportData.backupTransport;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -28,7 +30,6 @@ import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -41,7 +42,6 @@ import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toList;

import android.app.Application;
import android.app.IActivityManager;
import android.app.IBackupAgent;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
@@ -52,12 +52,10 @@ import android.app.backup.FullBackupDataOutput;
import android.app.backup.IBackupManager;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.IBackupObserver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -65,7 +63,6 @@ import android.os.PowerManager;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
import android.util.SparseArray;

import com.android.internal.backup.IBackupTransport;
import com.android.server.backup.internal.BackupHandler;
@@ -159,33 +156,24 @@ public class PerformBackupTaskTest {
        PackageManager packageManager = application.getPackageManager();
        mShadowPackageManager = Shadow.extract(packageManager);

        PowerManager powerManager =
                (PowerManager) application.getSystemService(Context.POWER_SERVICE);
        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
        mWakeLock = createBackupWakeLock(application);

        // Robolectric simulates multi-thread in a single-thread to avoid flakiness
        HandlerThread backupThread = new HandlerThread("backup");
        backupThread.setUncaughtExceptionHandler(
                (t, e) -> fail("Uncaught exception " + e.getMessage()));
        backupThread.start();
        Looper backupLooper = backupThread.getLooper();
        Looper backupLooper = startBackupThreadAndGetLooper();
        mShadowBackupLooper = shadowOf(backupLooper);
        mBackupHandler = new BackupHandler(mBackupManagerService, backupLooper);

        mBackupManager = spy(FakeIBackupManager.class);

        when(mBackupManagerService.getTransportManager()).thenReturn(mTransportManager);
        when(mBackupManagerService.getContext()).thenReturn(application);
        when(mBackupManagerService.getPackageManager()).thenReturn(packageManager);
        when(mBackupManagerService.getWakelock()).thenReturn(mWakeLock);
        when(mBackupManagerService.getCurrentOpLock()).thenReturn(new Object());
        when(mBackupManagerService.getQueueLock()).thenReturn(new Object());
        setUpBackupManagerServiceBasics(
                mBackupManagerService,
                application,
                mTransportManager,
                packageManager,
                mBackupHandler,
                mWakeLock);
        when(mBackupManagerService.getBaseStateDir()).thenReturn(mBaseStateDir);
        when(mBackupManagerService.getDataDir()).thenReturn(dataDir);
        when(mBackupManagerService.getCurrentOperations()).thenReturn(new SparseArray<>());
        when(mBackupManagerService.getBackupHandler()).thenReturn(mBackupHandler);
        when(mBackupManagerService.getBackupManagerBinder()).thenReturn(mBackupManager);
        when(mBackupManagerService.getActivityManager()).thenReturn(mock(IActivityManager.class));
    }

    @Test
@@ -282,6 +270,22 @@ public class PerformBackupTaskTest {
        verify(mObserver).backupFinished(eq(BackupManager.SUCCESS));
    }

    @Test
    public void testRunTask_releasesWakeLock() throws Exception {
        TransportMock transportMock = setUpTransport(mTransport);
        setUpAgent(PACKAGE_1);
        PerformBackupTask task =
                createPerformBackupTask(
                        transportMock.transportClient,
                        mTransport.transportDirName,
                        emptyList(),
                        PACKAGE_1);

        runTask(task);

        assertThat(mWakeLock.isHeld()).isFalse();
    }

    @Test
    public void testRunTask_callsTransportPerformBackupWithAgentData() throws Exception {
        TransportMock transportMock = setUpTransport(mTransport);
+4 −12
Original line number Diff line number Diff line
@@ -49,7 +49,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.platform.test.annotations.Presubmit;

import com.android.server.backup.testing.ShadowContextImplForBackup;
import com.android.server.backup.testing.TransportData;
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
import com.android.server.backup.transport.OnTransportRegisteredListener;
@@ -61,7 +60,6 @@ import com.android.server.testing.SystemLoaderPackages;
import com.android.server.testing.shadows.FrameworkShadowContextImpl;
import com.android.server.testing.shadows.FrameworkShadowPackageManager;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -90,8 +88,8 @@ public class TransportManagerTest {
    private static final String PACKAGE_B = "some.package.b";

    /**
     * GMSCore depends on this constant so we define it here on top of the definition in
     * {@link TransportManager} to verify this extra is passed
     * GMSCore depends on this constant so we define it here on top of the definition in {@link
     * TransportManager} to verify this extra is passed
     */
    private static final String EXTRA_TRANSPORT_REGISTRATION = "transport_registration";

@@ -108,21 +106,15 @@ public class TransportManagerTest {
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        mContext = RuntimeEnvironment.application;
        mShadowPackageManager =
                (FrameworkShadowPackageManager)
                        extract(RuntimeEnvironment.application.getPackageManager());
        mContext = RuntimeEnvironment.application.getApplicationContext();
                (FrameworkShadowPackageManager) extract(mContext.getPackageManager());

        mTransportA1 = genericTransport(PACKAGE_A, "TransportFoo");
        mTransportA2 = genericTransport(PACKAGE_A, "TransportBar");
        mTransportB1 = genericTransport(PACKAGE_B, "TransportBaz");
    }

    @After
    public void tearDown() throws Exception {
        ShadowContextImplForBackup.resetBackupShadowState();
    }

    @Test
    public void testRegisterTransports() throws Exception {
        setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+205 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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 com.android.server.backup.restore;

import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBackupManagerServiceBasics;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThreadAndGetLooper;
import static com.android.server.backup.testing.TransportData.backupTransport;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.AdditionalMatchers.aryEq;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import static org.testng.Assert.expectThrows;

import android.app.Application;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.IRestoreObserver;
import android.app.backup.IRestoreSession;
import android.app.backup.RestoreSet;
import android.os.Looper;
import android.os.PowerManager;
import android.platform.test.annotations.Presubmit;

import com.android.server.EventLogTags;
import com.android.server.backup.BackupManagerService;
import com.android.server.backup.TransportManager;
import com.android.server.backup.internal.BackupHandler;
import com.android.server.backup.testing.TransportData;
import com.android.server.backup.testing.TransportTestUtils;
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
import com.android.server.testing.FrameworkRobolectricTestRunner;
import com.android.server.testing.SystemLoaderPackages;
import com.android.server.testing.shadows.ShadowEventLog;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.shadows.ShadowLooper;

@RunWith(FrameworkRobolectricTestRunner.class)
@Config(manifest = Config.NONE, sdk = 26, shadows = ShadowEventLog.class)
@SystemLoaderPackages({"com.android.server.backup"})
@Presubmit
public class ActiveRestoreSessionTest {
    private static final String PACKAGE_1 = "com.example.package1";
    private static final String PACKAGE_2 = "com.example.package2";

    @Mock private BackupManagerService mBackupManagerService;
    @Mock private TransportManager mTransportManager;
    @Mock private IRestoreObserver mObserver;
    @Mock private IBackupManagerMonitor mMonitor;
    private ShadowLooper mShadowBackupLooper;
    private ShadowApplication mShadowApplication;
    private PowerManager.WakeLock mWakeLock;
    private TransportData mTransport;
    private RestoreSet mRestoreSet1;
    private RestoreSet mRestoreSet2;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        mTransport = backupTransport();

        mRestoreSet1 = new RestoreSet("name1", "device1", 1L);
        mRestoreSet2 = new RestoreSet("name2", "device2", 2L);

        Application application = RuntimeEnvironment.application;
        mShadowApplication = shadowOf(application);

        Looper backupLooper = startBackupThreadAndGetLooper();
        mShadowBackupLooper = shadowOf(backupLooper);
        BackupHandler backupHandler = new BackupHandler(mBackupManagerService, backupLooper);

        mWakeLock = createBackupWakeLock(application);

        setUpBackupManagerServiceBasics(
                mBackupManagerService,
                application,
                mTransportManager,
                application.getPackageManager(),
                backupHandler,
                mWakeLock);
    }

    @Test
    public void testGetAvailableRestoreSets_withoutPermission() throws Exception {
        mShadowApplication.denyPermissions(android.Manifest.permission.BACKUP);
        setUpTransport(mTransport);
        IRestoreSession restoreSession = createActiveRestoreSession(PACKAGE_1, mTransport);

        expectThrows(
                SecurityException.class,
                () -> restoreSession.getAvailableRestoreSets(mObserver, mMonitor));
    }

    @Test
    public void testGetAvailableRestoreSets_forNullObserver() throws Exception {
        mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
        setUpTransport(mTransport);
        IRestoreSession restoreSession = createActiveRestoreSession(PACKAGE_1, mTransport);

        expectThrows(
                RuntimeException.class,
                () -> restoreSession.getAvailableRestoreSets(null, mMonitor));
    }

    @Test
    public void testGetAvailableRestoreSets_whenTransportNotRegistered() throws Exception {
        mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
        setUpTransport(mTransport.unregistered());
        IRestoreSession restoreSession = createActiveRestoreSession(PACKAGE_1, mTransport);

        int result = restoreSession.getAvailableRestoreSets(mObserver, mMonitor);

        assertThat(result).isEqualTo(-1);
    }

    @Test
    public void testGetAvailableRestoreSets() throws Exception {
        mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
        TransportMock transportMock = setUpTransport(mTransport);
        when(transportMock.transport.getAvailableRestoreSets())
                .thenReturn(new RestoreSet[] {mRestoreSet1, mRestoreSet2});
        IRestoreSession restoreSession = createActiveRestoreSession(PACKAGE_1, mTransport);

        int result = restoreSession.getAvailableRestoreSets(mObserver, mMonitor);

        mShadowBackupLooper.runToEndOfTasks();
        assertThat(result).isEqualTo(0);
        verify(mObserver)
                .restoreSetsAvailable(aryEq(new RestoreSet[] {mRestoreSet1, mRestoreSet2}));
        verify(mTransportManager)
                .disposeOfTransportClient(eq(transportMock.transportClient), any());
        assertThat(mWakeLock.isHeld()).isFalse();
    }

    @Test
    public void testGetAvailableRestoreSets_forEmptyRestoreSets() throws Exception {
        mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
        TransportMock transportMock = setUpTransport(mTransport);
        when(transportMock.transport.getAvailableRestoreSets()).thenReturn(new RestoreSet[0]);
        IRestoreSession restoreSession = createActiveRestoreSession(PACKAGE_1, mTransport);

        int result = restoreSession.getAvailableRestoreSets(mObserver, mMonitor);

        mShadowBackupLooper.runToEndOfTasks();
        assertThat(result).isEqualTo(0);
        verify(mObserver).restoreSetsAvailable(aryEq(new RestoreSet[0]));
        assertThat(ShadowEventLog.hasEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE)).isFalse();
    }

    @Test
    public void testGetAvailableRestoreSets_forNullRestoreSets() throws Exception {
        mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
        TransportMock transportMock = setUpTransport(mTransport);
        when(transportMock.transport.getAvailableRestoreSets()).thenReturn(null);
        IRestoreSession restoreSession = createActiveRestoreSession(PACKAGE_1, mTransport);

        int result = restoreSession.getAvailableRestoreSets(mObserver, mMonitor);

        mShadowBackupLooper.runToEndOfTasks();
        assertThat(result).isEqualTo(0);
        verify(mObserver).restoreSetsAvailable(isNull());
        assertThat(ShadowEventLog.hasEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE)).isTrue();
        verify(mTransportManager)
                .disposeOfTransportClient(eq(transportMock.transportClient), any());
        assertThat(mWakeLock.isHeld()).isFalse();
    }

    private IRestoreSession createActiveRestoreSession(
            String packageName, TransportData transport) {
        return new ActiveRestoreSession(
                mBackupManagerService, packageName, transport.transportName);
    }

    private TransportMock setUpTransport(TransportData transport) throws Exception {
        return TransportTestUtils.setUpTransport(mTransportManager, transport);
    }
}
+95 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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 com.android.server.backup.testing;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.app.Application;
import android.app.IActivityManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.PowerManager;
import android.util.SparseArray;

import com.android.server.backup.BackupManagerService;
import com.android.server.backup.TransportManager;
import com.android.server.backup.internal.BackupHandler;

import java.lang.Thread.UncaughtExceptionHandler;

public class BackupManagerServiceTestUtils {
    /** Sets up a basic mocks for {@link BackupManagerService} */
    public static void setUpBackupManagerServiceBasics(
            BackupManagerService backupManagerService,
            Context context,
            TransportManager transportManager,
            PackageManager packageManager,
            BackupHandler backupHandler,
            PowerManager.WakeLock wakeLock) {
        when(backupManagerService.getContext()).thenReturn(context);
        when(backupManagerService.getTransportManager()).thenReturn(transportManager);
        when(backupManagerService.getPackageManager()).thenReturn(packageManager);
        when(backupManagerService.getBackupHandler()).thenReturn(backupHandler);
        when(backupManagerService.getCurrentOpLock()).thenReturn(new Object());
        when(backupManagerService.getQueueLock()).thenReturn(new Object());
        when(backupManagerService.getCurrentOperations()).thenReturn(new SparseArray<>());
        when(backupManagerService.getActivityManager()).thenReturn(mock(IActivityManager.class));
        when(backupManagerService.getWakelock()).thenReturn(wakeLock);
    }

    public static PowerManager.WakeLock createBackupWakeLock(Application application) {
        PowerManager powerManager =
                (PowerManager) application.getSystemService(Context.POWER_SERVICE);
        return powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
    }

    /**
     * Creates a backup thread associated with a looper, starts it and returns its looper for
     * shadowing and creation of the backup handler.
     *
     * <p>Note that Robolectric simulates multi-thread in a single-thread to avoid flakiness, so
     * even though we started the thread, you should control its execution via the shadow of the
     * looper returned.
     *
     * @return The {@link Looper} for the backup thread.
     */
    public static Looper startBackupThreadAndGetLooper() {
        HandlerThread backupThread = new HandlerThread("backup");
        backupThread.start();
        return backupThread.getLooper();
    }

    /**
     * Similar to {@link #startBackupThreadAndGetLooper()} but with a custom exception handler and
     * returning the thread instead of the looper associated with it.
     *
     * @param exceptionHandler Uncaught exception handler for backup thread.
     * @return The backup thread.
     * @see #startBackupThreadAndGetLooper()
     */
    public static HandlerThread startBackupThread(UncaughtExceptionHandler exceptionHandler) {
        HandlerThread backupThread = new HandlerThread("backup");
        backupThread.setUncaughtExceptionHandler(exceptionHandler);
        backupThread.start();
        return backupThread;
    }

    private BackupManagerServiceTestUtils() {}
}
Loading