summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/backup/backuplib/java/com/android/server/backup/transport/DelegatingTransport.java414
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/transport/DelegatingTransportTest.java386
2 files changed, 800 insertions, 0 deletions
diff --git a/services/backup/backuplib/java/com/android/server/backup/transport/DelegatingTransport.java b/services/backup/backuplib/java/com/android/server/backup/transport/DelegatingTransport.java
new file mode 100644
index 000000000000..ab870803e60d
--- /dev/null
+++ b/services/backup/backuplib/java/com/android/server/backup/transport/DelegatingTransport.java
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2019 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.transport;
+
+import android.app.backup.BackupAgent;
+import android.app.backup.BackupTransport;
+import android.app.backup.RestoreDescription;
+import android.app.backup.RestoreSet;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+
+import com.android.internal.backup.IBackupTransport;
+
+/**
+ * Delegates all transport methods to the delegate() implemented in the derived class.
+ */
+public abstract class DelegatingTransport extends IBackupTransport.Stub {
+ protected abstract IBackupTransport getDelegate() throws RemoteException;
+
+ /**
+ * Ask the transport for the name under which it should be registered. This will
+ * typically be its host service's component name, but need not be.
+ */
+ @Override
+ public String name() throws RemoteException {
+ return getDelegate().name();
+ }
+
+ /**
+ * Ask the transport for an Intent that can be used to launch any internal
+ * configuration Activity that it wishes to present. For example, the transport
+ * may offer a UI for allowing the user to supply login credentials for the
+ * transport's off-device backend.
+ *
+ * If the transport does not supply any user-facing configuration UI, it should
+ * return null from this method.
+ *
+ * @return An Intent that can be passed to Context.startActivity() in order to
+ * launch the transport's configuration UI. This method will return null
+ * if the transport does not offer any user-facing configuration UI.
+ */
+ @Override
+ public Intent configurationIntent() throws RemoteException {
+ return getDelegate().configurationIntent();
+ }
+
+ /**
+ * On demand, supply a one-line string that can be shown to the user that
+ * describes the current backend destination. For example, a transport that
+ * can potentially associate backup data with arbitrary user accounts should
+ * include the name of the currently-active account here.
+ *
+ * @return A string describing the destination to which the transport is currently
+ * sending data. This method should not return null.
+ */
+ @Override
+ public String currentDestinationString() throws RemoteException {
+ return getDelegate().currentDestinationString();
+ }
+
+ /**
+ * Ask the transport for an Intent that can be used to launch a more detailed
+ * secondary data management activity. For example, the configuration intent might
+ * be one for allowing the user to select which account they wish to associate
+ * their backups with, and the management intent might be one which presents a
+ * UI for managing the data on the backend.
+ *
+ * <p>In the Settings UI, the configuration intent will typically be invoked
+ * when the user taps on the preferences item labeled with the current
+ * destination string, and the management intent will be placed in an overflow
+ * menu labelled with the management label string.
+ *
+ * <p>If the transport does not supply any user-facing data management
+ * UI, then it should return {@code null} from this method.
+ *
+ * @return An intent that can be passed to Context.startActivity() in order to
+ * launch the transport's data-management UI. This method will return
+ * {@code null} if the transport does not offer any user-facing data
+ * management UI.
+ */
+ @Override
+ public Intent dataManagementIntent() throws RemoteException {
+ return getDelegate().dataManagementIntent();
+ }
+
+ /**
+ * On demand, supply a short {@link CharSequence} that can be shown to the user as the
+ * label on
+ * an overflow menu item used to invoke the data management UI.
+ *
+ * @return A {@link CharSequence} to be used as the label for the transport's data management
+ * affordance. If the transport supplies a data management intent, this
+ * method must not return {@code null}.
+ */
+ @Override
+ public CharSequence dataManagementIntentLabel() throws RemoteException {
+ return getDelegate().dataManagementIntentLabel();
+ }
+
+ /**
+ * Ask the transport where, on local device storage, to keep backup state blobs.
+ * This is per-transport so that mock transports used for testing can coexist with
+ * "live" backup services without interfering with the live bookkeeping. The
+ * returned string should be a name that is expected to be unambiguous among all
+ * available backup transports; the name of the class implementing the transport
+ * is a good choice. This MUST be constant.
+ *
+ * @return A unique name, suitable for use as a file or directory name, that the
+ * Backup Manager could use to disambiguate state files associated with
+ * different backup transports.
+ */
+ @Override
+ public String transportDirName() throws RemoteException {
+ return getDelegate().transportDirName();
+ }
+
+ /**
+ * Verify that this is a suitable time for a backup pass. This should return zero
+ * if a backup is reasonable right now, some positive value otherwise. This method
+ * will be called outside of the {@link #startSession}/{@link #endSession} pair.
+ *
+ * <p>If this is not a suitable time for a backup, the transport should return a
+ * backoff delay, in milliseconds, after which the Backup Manager should try again.
+ *
+ * @return Zero if this is a suitable time for a backup pass, or a positive time delay
+ * in milliseconds to suggest deferring the backup pass for a while.
+ */
+ @Override
+ public long requestBackupTime() throws RemoteException {
+ return getDelegate().requestBackupTime();
+ }
+
+ /**
+ * Initialize the server side storage for this device, erasing all stored data.
+ * The transport may send the request immediately, or may buffer it. After
+ * this is called, {@link #finishBackup} must be called to ensure the request
+ * is sent and received successfully.
+ *
+ * @return One of {@link BackupConstants#TRANSPORT_OK} (OK so far) or
+ * {@link BackupConstants#TRANSPORT_ERROR} (on network error or other failure).
+ */
+ @Override
+ public int initializeDevice() throws RemoteException {
+ return getDelegate().initializeDevice();
+ }
+
+ /**
+ * Send one application's data to the backup destination. The transport may send
+ * the data immediately, or may buffer it. After this is called, {@link #finishBackup}
+ * must be called to ensure the data is sent and recorded successfully.
+ *
+ * @param packageInfo The identity of the application whose data is being backed up.
+ * This specifically includes the signature list for the package.
+ * @param inFd Descriptor of file with data that resulted from invoking the application's
+ * BackupService.doBackup() method. This may be a pipe rather than a file on
+ * persistent media, so it may not be seekable.
+ * @param flags Some of {@link BackupTransport#FLAG_USER_INITIATED}.
+ * @return one of {@link BackupConstants#TRANSPORT_OK} (OK so far),
+ * {@link BackupConstants#TRANSPORT_ERROR} (on network error or other failure), or
+ * {@link BackupConstants#TRANSPORT_NOT_INITIALIZED} (if the backend dataset has
+ * become lost due to inactive expiry or some other reason and needs re-initializing)
+ */
+ @Override
+ public int performBackup(PackageInfo packageInfo,
+ ParcelFileDescriptor inFd, int flags) throws RemoteException {
+ return getDelegate().performBackup(packageInfo, inFd, flags);
+ }
+
+ /**
+ * Erase the give application's data from the backup destination. This clears
+ * out the given package's data from the current backup set, making it as though
+ * the app had never yet been backed up. After this is called, {@link finishBackup}
+ * must be called to ensure that the operation is recorded successfully.
+ *
+ * @return the same error codes as {@link #performBackup}.
+ * @param packageInfo
+ */
+ @Override
+ public int clearBackupData(PackageInfo packageInfo) throws RemoteException {
+ return getDelegate().clearBackupData(packageInfo);
+ }
+
+ /**
+ * Finish sending application data to the backup destination. This must be
+ * called after {@link #performBackup} or {@link clearBackupData} to ensure that
+ * all data is sent. Only when this method returns true can a backup be assumed
+ * to have succeeded.
+ *
+ * @return the same error codes as {@link #performBackup}.
+ */
+ @Override
+ public int finishBackup() throws RemoteException {
+ return getDelegate().finishBackup();
+ }
+
+ /**
+ * Get the set of all backups currently available over this transport.
+ *
+ * @return Descriptions of the set of restore images available for this device,
+ * or null if an error occurred (the attempt should be rescheduled).
+ **/
+ @Override
+ public RestoreSet[] getAvailableRestoreSets() throws RemoteException {
+ return getDelegate().getAvailableRestoreSets();
+ }
+
+ /**
+ * Get the identifying token of the backup set currently being stored from
+ * this device. This is used in the case of applications wishing to restore
+ * their last-known-good data.
+ *
+ * @return A token that can be passed to {@link #startRestore}, or 0 if there
+ * is no backup set available corresponding to the current device state.
+ */
+ @Override
+ public long getCurrentRestoreSet() throws RemoteException {
+ return getDelegate().getCurrentRestoreSet();
+ }
+
+ /**
+ * Start restoring application data from backup. After calling this function,
+ * alternate calls to {@link #nextRestorePackage} and {@link #nextRestoreData}
+ * to walk through the actual application data.
+ *
+ * @param token A backup token as returned by {@link #getAvailableRestoreSets}
+ * or {@link #getCurrentRestoreSet}.
+ * @param packages List of applications to restore (if data is available).
+ * Application data will be restored in the order given.
+ * @return One of {@link BackupConstants#TRANSPORT_OK} (OK so far, call
+ * {@link #nextRestorePackage}) or {@link BackupConstants#TRANSPORT_ERROR}
+ * (an error occurred, the restore should be aborted and rescheduled).
+ */
+ @Override
+ public int startRestore(long token, PackageInfo[] packages) throws RemoteException {
+ return getDelegate().startRestore(token, packages);
+ }
+
+ /**
+ * Get the package name of the next application with data in the backup store, plus
+ * a description of the structure of the restored archive: either TYPE_KEY_VALUE for
+ * an original-API key/value dataset, or TYPE_FULL_STREAM for a tarball-type archive stream.
+ *
+ * <p>If the package name in the returned RestoreDescription object is the singleton
+ * {@link RestoreDescription#NO_MORE_PACKAGES}, it indicates that no further data is available
+ * in the current restore session: all packages described in startRestore() have been
+ * processed.
+ *
+ * <p>If this method returns {@code null}, it means that a transport-level error has
+ * occurred and the entire restore operation should be abandoned.
+ *
+ * @return A RestoreDescription object containing the name of one of the packages
+ * supplied to {@link #startRestore} plus an indicator of the data type of that
+ * restore data; or {@link RestoreDescription#NO_MORE_PACKAGES} to indicate that
+ * no more packages can be restored in this session; or {@code null} to indicate
+ * a transport-level error.
+ */
+ @Override
+ public RestoreDescription nextRestorePackage() throws RemoteException {
+ return getDelegate().nextRestorePackage();
+ }
+
+ /**
+ * Get the data for the application returned by {@link #nextRestorePackage}.
+ *
+ * @param outFd An open, writable file into which the backup data should be stored.
+ * @return the same error codes as {@link #startRestore}.
+ */
+ @Override
+ public int getRestoreData(ParcelFileDescriptor outFd) throws RemoteException {
+ return getDelegate().getRestoreData(outFd);
+ }
+
+ /**
+ * End a restore session (aborting any in-process data transfer as necessary),
+ * freeing any resources and connections used during the restore process.
+ */
+ @Override
+ public void finishRestore() throws RemoteException {
+ getDelegate().finishRestore();
+ }
+
+ @Override
+ public long requestFullBackupTime() throws RemoteException {
+ return getDelegate().requestFullBackupTime();
+ }
+
+ @Override
+ public int performFullBackup(PackageInfo targetPackage,
+ ParcelFileDescriptor socket, int flags) throws RemoteException {
+ return getDelegate().performFullBackup(targetPackage, socket, flags);
+ }
+
+ @Override
+ public int checkFullBackupSize(long size) throws RemoteException {
+ return getDelegate().checkFullBackupSize(size);
+ }
+
+ @Override
+ public int sendBackupData(int numBytes) throws RemoteException {
+ return getDelegate().sendBackupData(numBytes);
+ }
+
+ @Override
+ public void cancelFullBackup() throws RemoteException {
+ getDelegate().cancelFullBackup();
+ }
+
+ /**
+ * Ask the transport whether this app is eligible for backup.
+ *
+ * @param targetPackage The identity of the application.
+ * @param isFullBackup If set, transport should check if app is eligible for full data backup,
+ * otherwise to check if eligible for key-value backup.
+ * @return Whether this app is eligible for backup.
+ */
+ @Override
+ public boolean isAppEligibleForBackup(PackageInfo targetPackage,
+ boolean isFullBackup) throws RemoteException {
+ return getDelegate().isAppEligibleForBackup(targetPackage, isFullBackup);
+ }
+
+ /**
+ * Ask the transport about current quota for backup size of the package.
+ *
+ * @param packageName ID of package to provide the quota.
+ * @param isFullBackup If set, transport should return limit for full data backup, otherwise
+ * for key-value backup.
+ * @return Current limit on full data backup size in bytes.
+ */
+ @Override
+ public long getBackupQuota(String packageName, boolean isFullBackup) throws RemoteException {
+ return getDelegate().getBackupQuota(packageName, isFullBackup);
+ }
+
+ /**
+ * Ask the transport to provide data for the "current" package being restored. This
+ * is the package that was just reported by {@link #nextRestorePackage()} as having
+ * {@link RestoreDescription#TYPE_FULL_STREAM} data.
+ *
+ * The transport writes some data to the socket supplied to this call, and returns
+ * the number of bytes written. The system will then read that many bytes and
+ * stream them to the application's agent for restore, then will call this method again
+ * to receive the next chunk of the archive. This sequence will be repeated until the
+ * transport returns zero indicating that all of the package's data has been delivered
+ * (or returns a negative value indicating some sort of hard error condition at the
+ * transport level).
+ *
+ * <p>After this method returns zero, the system will then call
+ * {@link #getNextFullRestorePackage()} to begin the restore process for the next
+ * application, and the sequence begins again.
+ *
+ * <p>The transport should always close this socket when returning from this method.
+ * Do not cache this socket across multiple calls or you may leak file descriptors.
+ *
+ * @param socket The file descriptor that the transport will use for delivering the
+ * streamed archive. The transport must close this socket in all cases when returning
+ * from this method.
+ * @return 0 when no more data for the current package is available. A positive value
+ * indicates the presence of that many bytes to be delivered to the app. Any negative
+ * return value is treated as equivalent to {@link BackupTransport#TRANSPORT_ERROR},
+ * indicating a fatal error condition that precludes further restore operations
+ * on the current dataset.
+ */
+ @Override
+ public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) throws RemoteException {
+ return getDelegate().getNextFullRestoreDataChunk(socket);
+ }
+
+ /**
+ * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM}
+ * data for restore, it will invoke this method to tell the transport that it should
+ * abandon the data download for the current package. The OS will then either call
+ * {@link #nextRestorePackage()} again to move on to restoring the next package in the
+ * set being iterated over, or will call {@link #finishRestore()} to shut down the restore
+ * operation.
+ *
+ * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the
+ * current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious
+ * transport-level failure. If the transport reports an error here, the entire restore
+ * operation will immediately be finished with no further attempts to restore app data.
+ */
+ @Override
+ public int abortFullRestore() throws RemoteException {
+ return getDelegate().abortFullRestore();
+ }
+
+ /**
+ * Returns flags with additional information about the transport, which is accessible to the
+ * {@link BackupAgent}. This allows the agent to decide what to backup or
+ * restore based on properties of the transport.
+ *
+ * <p>For supported flags see {@link BackupAgent}.
+ */
+ @Override
+ public int getTransportFlags() throws RemoteException {
+ return getDelegate().getTransportFlags();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/transport/DelegatingTransportTest.java b/services/tests/servicestests/src/com/android/server/backup/transport/DelegatingTransportTest.java
new file mode 100644
index 000000000000..bae11eb86b32
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/transport/DelegatingTransportTest.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2019 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.transport;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.app.backup.RestoreDescription;
+import android.app.backup.RestoreSet;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.backup.IBackupTransport;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class DelegatingTransportTest {
+ @Mock private IBackupTransport mBackupTransport;
+ @Mock private PackageInfo mPackageInfo;
+ @Mock private ParcelFileDescriptor mFd;
+
+ private final String mPackageName = "testpackage";
+ private final RestoreSet mRestoreSet = new RestoreSet();
+ private final int mFlags = 1;
+ private final long mRestoreToken = 10;
+ private final long mSize = 100;
+ private final int mNumBytes = 1000;
+ private DelegatingTransport mDelegatingTransport;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mDelegatingTransport = new DelegatingTransport() {
+ @Override
+ protected IBackupTransport getDelegate() {
+ return mBackupTransport;
+ }
+ };
+ }
+
+ @Test
+ public void testName() throws RemoteException {
+ String exp = "dummy";
+ when(mBackupTransport.name()).thenReturn(exp);
+
+ String ret = mDelegatingTransport.name();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).name();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testConfigurationIntent() throws RemoteException {
+ Intent exp = new Intent("dummy");
+ when(mBackupTransport.configurationIntent()).thenReturn(exp);
+
+ Intent ret = mDelegatingTransport.configurationIntent();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).configurationIntent();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testCurrentDestinationString() throws RemoteException {
+ String exp = "dummy";
+ when(mBackupTransport.currentDestinationString()).thenReturn(exp);
+
+ String ret = mDelegatingTransport.currentDestinationString();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).currentDestinationString();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testDataManagementIntent() throws RemoteException {
+ Intent exp = new Intent("dummy");
+ when(mBackupTransport.dataManagementIntent()).thenReturn(exp);
+
+ Intent ret = mDelegatingTransport.dataManagementIntent();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).dataManagementIntent();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testDataManagementIntentLabel() throws RemoteException {
+ String exp = "dummy";
+ when(mBackupTransport.dataManagementIntentLabel()).thenReturn(exp);
+
+ CharSequence ret = mDelegatingTransport.dataManagementIntentLabel();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).dataManagementIntentLabel();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testTransportDirName() throws RemoteException {
+ String exp = "dummy";
+ when(mBackupTransport.transportDirName()).thenReturn(exp);
+
+ String ret = mDelegatingTransport.transportDirName();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).transportDirName();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testRequestBackupTime() throws RemoteException {
+ long exp = 1000L;
+ when(mBackupTransport.requestBackupTime()).thenReturn(exp);
+
+ long ret = mDelegatingTransport.requestBackupTime();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).requestBackupTime();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testInitializeDevice() throws RemoteException {
+ int exp = 1000;
+ when(mBackupTransport.initializeDevice()).thenReturn(exp);
+
+ long ret = mDelegatingTransport.initializeDevice();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).initializeDevice();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testPerformBackup() throws RemoteException {
+ int exp = 1000;
+ when(mBackupTransport.performBackup(mPackageInfo, mFd, mFlags)).thenReturn(exp);
+
+ int ret = mDelegatingTransport.performBackup(mPackageInfo, mFd, mFlags);
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).performBackup(mPackageInfo, mFd, mFlags);
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testClearBackupData() throws RemoteException {
+ int exp = 1000;
+ when(mBackupTransport.clearBackupData(mPackageInfo)).thenReturn(exp);
+
+ int ret = mDelegatingTransport.clearBackupData(mPackageInfo);
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).clearBackupData(mPackageInfo);
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testFinishBackup() throws RemoteException {
+ int exp = 1000;
+ when(mBackupTransport.finishBackup()).thenReturn(exp);
+
+ int ret = mDelegatingTransport.finishBackup();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).finishBackup();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testGetAvailableRestoreSets() throws RemoteException {
+ RestoreSet[] exp = new RestoreSet[] {mRestoreSet};
+ when(mBackupTransport.getAvailableRestoreSets()).thenReturn(exp);
+
+ RestoreSet[] ret = mDelegatingTransport.getAvailableRestoreSets();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).getAvailableRestoreSets();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testGetCurrentRestoreSet() throws RemoteException {
+ long exp = 1000;
+ when(mBackupTransport.getCurrentRestoreSet()).thenReturn(exp);
+
+ long ret = mDelegatingTransport.getCurrentRestoreSet();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).getCurrentRestoreSet();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testStartRestore() throws RemoteException {
+ int exp = 1000;
+ PackageInfo[] packageInfos = {mPackageInfo};
+ when(mBackupTransport.startRestore(mRestoreToken, packageInfos)).thenReturn(exp);
+
+ int ret = mDelegatingTransport.startRestore(mRestoreToken, packageInfos);
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).startRestore(mRestoreToken, packageInfos);
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testNextRestorePackage() throws RemoteException {
+ RestoreDescription exp = new RestoreDescription(mPackageName, 1);
+ when(mBackupTransport.nextRestorePackage()).thenReturn(exp);
+
+ RestoreDescription ret = mDelegatingTransport.nextRestorePackage();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).nextRestorePackage();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testGetRestoreData() throws RemoteException {
+ int exp = 1000;
+ when(mBackupTransport.getRestoreData(mFd)).thenReturn(exp);
+
+ int ret = mDelegatingTransport.getRestoreData(mFd);
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).getRestoreData(mFd);
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void tesFinishRestore() throws RemoteException {
+ mDelegatingTransport.finishRestore();
+
+ verify(mBackupTransport, times(1)).finishRestore();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testRequestFullBackupTime() throws RemoteException {
+ long exp = 1000L;
+ when(mBackupTransport.requestFullBackupTime()).thenReturn(exp);
+
+ long ret = mDelegatingTransport.requestFullBackupTime();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).requestFullBackupTime();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testPerformFullBackup() throws RemoteException {
+ int exp = 1000;
+ when(mBackupTransport.performFullBackup(mPackageInfo, mFd, mFlags)).thenReturn(exp);
+
+ int ret = mDelegatingTransport.performFullBackup(mPackageInfo, mFd, mFlags);
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).performFullBackup(mPackageInfo, mFd, mFlags);
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testCheckFullBackupSize() throws RemoteException {
+ int exp = 1000;
+ when(mBackupTransport.checkFullBackupSize(mSize)).thenReturn(exp);
+
+ int ret = mDelegatingTransport.checkFullBackupSize(mSize);
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).checkFullBackupSize(mSize);
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testSendBackupData() throws RemoteException {
+ int exp = 1000;
+ when(mBackupTransport.sendBackupData(mNumBytes)).thenReturn(exp);
+
+ int ret = mDelegatingTransport.sendBackupData(mNumBytes);
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).sendBackupData(mNumBytes);
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testCancelFullBackup() throws RemoteException {
+ mDelegatingTransport.cancelFullBackup();
+
+ verify(mBackupTransport, times(1)).cancelFullBackup();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testIsAppEligibleForBackup() throws RemoteException {
+ boolean exp = true;
+ when(mBackupTransport.isAppEligibleForBackup(mPackageInfo, true)).thenReturn(exp);
+
+ boolean ret = mDelegatingTransport.isAppEligibleForBackup(mPackageInfo, true);
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).isAppEligibleForBackup(mPackageInfo, true);
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testGetBackupQuota() throws RemoteException {
+ long exp = 1000;
+ when(mBackupTransport.getBackupQuota(mPackageName, true)).thenReturn(exp);
+
+ long ret = mDelegatingTransport.getBackupQuota(mPackageName, true);
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).getBackupQuota(mPackageName, true);
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testGetNextFullRestoreDataChunk() throws RemoteException {
+ int exp = 1000;
+ when(mBackupTransport.getNextFullRestoreDataChunk(mFd)).thenReturn(exp);
+
+ int ret = mDelegatingTransport.getNextFullRestoreDataChunk(mFd);
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).getNextFullRestoreDataChunk(mFd);
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testAbortFullRestore() throws RemoteException {
+ int exp = 1000;
+ when(mBackupTransport.abortFullRestore()).thenReturn(exp);
+
+ int ret = mDelegatingTransport.abortFullRestore();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).abortFullRestore();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+
+ @Test
+ public void testGetTransportFlags() throws RemoteException {
+ int exp = 1000;
+ when(mBackupTransport.getTransportFlags()).thenReturn(exp);
+
+ int ret = mDelegatingTransport.getTransportFlags();
+
+ assertEquals(exp, ret);
+ verify(mBackupTransport, times(1)).getTransportFlags();
+ verifyNoMoreInteractions(mBackupTransport);
+ }
+}