Update BackupTransportCallback to use async AIDL
Bug: 202716271
Test: 1. Unit tests WIP
2. atest CtsBackupTestCases CtsBackupHostTestCases
GtsBackupTestCases GtsBackupHostTestCases
Change-Id: Ifa45f35a415ef3c5fbab03696456fd7085568a7b
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
package com.android.server.backup.transport;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.backup.BackupTransport;
|
||||
import android.app.backup.RestoreDescription;
|
||||
import android.app.backup.RestoreSet;
|
||||
import android.content.Intent;
|
||||
@@ -24,50 +25,70 @@ import android.content.pm.PackageInfo;
|
||||
import android.os.Binder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.backup.IBackupTransport;
|
||||
import com.android.internal.infra.AndroidFuture;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* Client to {@link com.android.internal.backup.IBackupTransport}. Manages the call to the remote
|
||||
* transport service and delivers the results.
|
||||
*/
|
||||
public class BackupTransportClient {
|
||||
private static final String TAG = "BackupTransportClient";
|
||||
|
||||
private final IBackupTransport mTransportBinder;
|
||||
private final TransportStatusCallbackPool mCallbackPool;
|
||||
|
||||
BackupTransportClient(IBackupTransport transportBinder) {
|
||||
mTransportBinder = transportBinder;
|
||||
|
||||
// This is a temporary fix to allow blocking calls.
|
||||
// TODO: b/147702043. Redesign IBackupTransport so as to make the calls non-blocking.
|
||||
Binder.allowBlocking(mTransportBinder.asBinder());
|
||||
mCallbackPool = new TransportStatusCallbackPool();
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#name()}.
|
||||
*/
|
||||
public String name() throws RemoteException {
|
||||
return mTransportBinder.name();
|
||||
AndroidFuture<String> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.name(resultFuture);
|
||||
return getFutureResult(resultFuture);
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#configurationIntent()}
|
||||
*/
|
||||
public Intent configurationIntent() throws RemoteException {
|
||||
return mTransportBinder.configurationIntent();
|
||||
AndroidFuture<Intent> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.configurationIntent(resultFuture);
|
||||
return getFutureResult(resultFuture);
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#currentDestinationString()}
|
||||
*/
|
||||
public String currentDestinationString() throws RemoteException {
|
||||
return mTransportBinder.currentDestinationString();
|
||||
AndroidFuture<String> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.currentDestinationString(resultFuture);
|
||||
return getFutureResult(resultFuture);
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#dataManagementIntent()}
|
||||
*/
|
||||
public Intent dataManagementIntent() throws RemoteException {
|
||||
return mTransportBinder.dataManagementIntent();
|
||||
AndroidFuture<Intent> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.dataManagementIntent(resultFuture);
|
||||
return getFutureResult(resultFuture);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,42 +96,67 @@ public class BackupTransportClient {
|
||||
*/
|
||||
@Nullable
|
||||
public CharSequence dataManagementIntentLabel() throws RemoteException {
|
||||
return mTransportBinder.dataManagementIntentLabel();
|
||||
AndroidFuture<CharSequence> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.dataManagementIntentLabel(resultFuture);
|
||||
return getFutureResult(resultFuture);
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#transportDirName()}
|
||||
*/
|
||||
public String transportDirName() throws RemoteException {
|
||||
return mTransportBinder.transportDirName();
|
||||
AndroidFuture<String> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.transportDirName(resultFuture);
|
||||
return getFutureResult(resultFuture);
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#initializeDevice()}
|
||||
*/
|
||||
public int initializeDevice() throws RemoteException {
|
||||
return mTransportBinder.initializeDevice();
|
||||
TransportStatusCallback callback = mCallbackPool.acquire();
|
||||
try {
|
||||
mTransportBinder.initializeDevice(callback);
|
||||
return callback.getOperationStatus();
|
||||
} finally {
|
||||
mCallbackPool.recycle(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#clearBackupData(PackageInfo)}
|
||||
*/
|
||||
public int clearBackupData(PackageInfo packageInfo) throws RemoteException {
|
||||
return mTransportBinder.clearBackupData(packageInfo);
|
||||
TransportStatusCallback callback = mCallbackPool.acquire();
|
||||
try {
|
||||
mTransportBinder.clearBackupData(packageInfo, callback);
|
||||
return callback.getOperationStatus();
|
||||
} finally {
|
||||
mCallbackPool.recycle(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#finishBackup()}
|
||||
*/
|
||||
public int finishBackup() throws RemoteException {
|
||||
return mTransportBinder.finishBackup();
|
||||
TransportStatusCallback callback = mCallbackPool.acquire();
|
||||
try {
|
||||
mTransportBinder.finishBackup(callback);
|
||||
return callback.getOperationStatus();
|
||||
} finally {
|
||||
mCallbackPool.recycle(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#requestBackupTime()}
|
||||
*/
|
||||
public long requestBackupTime() throws RemoteException {
|
||||
return mTransportBinder.requestBackupTime();
|
||||
AndroidFuture<Long> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.requestBackupTime(resultFuture);
|
||||
Long result = getFutureResult(resultFuture);
|
||||
return result == null ? BackupTransport.TRANSPORT_ERROR : result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,56 +164,91 @@ public class BackupTransportClient {
|
||||
*/
|
||||
public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags)
|
||||
throws RemoteException {
|
||||
return mTransportBinder.performBackup(packageInfo, inFd, flags);
|
||||
TransportStatusCallback callback = mCallbackPool.acquire();
|
||||
try {
|
||||
mTransportBinder.performBackup(packageInfo, inFd, flags, callback);
|
||||
return callback.getOperationStatus();
|
||||
} finally {
|
||||
mCallbackPool.recycle(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#getAvailableRestoreSets()}
|
||||
*/
|
||||
public RestoreSet[] getAvailableRestoreSets() throws RemoteException {
|
||||
return mTransportBinder.getAvailableRestoreSets();
|
||||
AndroidFuture<List<RestoreSet>> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.getAvailableRestoreSets(resultFuture);
|
||||
List<RestoreSet> result = getFutureResult(resultFuture);
|
||||
return result == null ? null : result.toArray(new RestoreSet[] {});
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#getCurrentRestoreSet()}
|
||||
*/
|
||||
public long getCurrentRestoreSet() throws RemoteException {
|
||||
return mTransportBinder.getCurrentRestoreSet();
|
||||
AndroidFuture<Long> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.getCurrentRestoreSet(resultFuture);
|
||||
Long result = getFutureResult(resultFuture);
|
||||
return result == null ? BackupTransport.TRANSPORT_ERROR : result;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#startRestore(long, PackageInfo[])}
|
||||
*/
|
||||
public int startRestore(long token, PackageInfo[] packages) throws RemoteException {
|
||||
return mTransportBinder.startRestore(token, packages);
|
||||
TransportStatusCallback callback = mCallbackPool.acquire();
|
||||
try {
|
||||
mTransportBinder.startRestore(token, packages, callback);
|
||||
return callback.getOperationStatus();
|
||||
} finally {
|
||||
mCallbackPool.recycle(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#nextRestorePackage()}
|
||||
*/
|
||||
public RestoreDescription nextRestorePackage() throws RemoteException {
|
||||
return mTransportBinder.nextRestorePackage();
|
||||
AndroidFuture<RestoreDescription> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.nextRestorePackage(resultFuture);
|
||||
return getFutureResult(resultFuture);
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#getRestoreData(ParcelFileDescriptor)}
|
||||
*/
|
||||
public int getRestoreData(ParcelFileDescriptor outFd) throws RemoteException {
|
||||
return mTransportBinder.getRestoreData(outFd);
|
||||
TransportStatusCallback callback = mCallbackPool.acquire();
|
||||
try {
|
||||
mTransportBinder.getRestoreData(outFd, callback);
|
||||
return callback.getOperationStatus();
|
||||
} finally {
|
||||
mCallbackPool.recycle(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#finishRestore()}
|
||||
*/
|
||||
public void finishRestore() throws RemoteException {
|
||||
mTransportBinder.finishRestore();
|
||||
TransportStatusCallback callback = mCallbackPool.acquire();
|
||||
try {
|
||||
mTransportBinder.finishRestore(callback);
|
||||
callback.getOperationStatus();
|
||||
} finally {
|
||||
mCallbackPool.recycle(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#requestFullBackupTime()}
|
||||
*/
|
||||
public long requestFullBackupTime() throws RemoteException {
|
||||
return mTransportBinder.requestFullBackupTime();
|
||||
AndroidFuture<Long> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.requestFullBackupTime(resultFuture);
|
||||
Long result = getFutureResult(resultFuture);
|
||||
return result == null ? BackupTransport.TRANSPORT_ERROR : result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,28 +256,52 @@ public class BackupTransportClient {
|
||||
*/
|
||||
public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket,
|
||||
int flags) throws RemoteException {
|
||||
return mTransportBinder.performFullBackup(targetPackage, socket, flags);
|
||||
TransportStatusCallback callback = mCallbackPool.acquire();
|
||||
try {
|
||||
mTransportBinder.performFullBackup(targetPackage, socket, flags, callback);
|
||||
return callback.getOperationStatus();
|
||||
} finally {
|
||||
mCallbackPool.recycle(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#checkFullBackupSize(long)}
|
||||
*/
|
||||
public int checkFullBackupSize(long size) throws RemoteException {
|
||||
return mTransportBinder.checkFullBackupSize(size);
|
||||
TransportStatusCallback callback = mCallbackPool.acquire();
|
||||
try {
|
||||
mTransportBinder.checkFullBackupSize(size, callback);
|
||||
return callback.getOperationStatus();
|
||||
} finally {
|
||||
mCallbackPool.recycle(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#sendBackupData(int)}
|
||||
*/
|
||||
public int sendBackupData(int numBytes) throws RemoteException {
|
||||
return mTransportBinder.sendBackupData(numBytes);
|
||||
TransportStatusCallback callback = mCallbackPool.acquire();
|
||||
mTransportBinder.sendBackupData(numBytes, callback);
|
||||
try {
|
||||
return callback.getOperationStatus();
|
||||
} finally {
|
||||
mCallbackPool.recycle(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#cancelFullBackup()}
|
||||
*/
|
||||
public void cancelFullBackup() throws RemoteException {
|
||||
mTransportBinder.cancelFullBackup();
|
||||
TransportStatusCallback callback = mCallbackPool.acquire();
|
||||
try {
|
||||
mTransportBinder.cancelFullBackup(callback);
|
||||
callback.getOperationStatus();
|
||||
} finally {
|
||||
mCallbackPool.recycle(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,34 +309,93 @@ public class BackupTransportClient {
|
||||
*/
|
||||
public boolean isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup)
|
||||
throws RemoteException {
|
||||
return mTransportBinder.isAppEligibleForBackup(targetPackage, isFullBackup);
|
||||
AndroidFuture<Boolean> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.isAppEligibleForBackup(targetPackage, isFullBackup, resultFuture);
|
||||
Boolean result = getFutureResult(resultFuture);
|
||||
return result != null && result;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#getBackupQuota(String, boolean)}
|
||||
*/
|
||||
public long getBackupQuota(String packageName, boolean isFullBackup) throws RemoteException {
|
||||
return mTransportBinder.getBackupQuota(packageName, isFullBackup);
|
||||
AndroidFuture<Long> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.getBackupQuota(packageName, isFullBackup, resultFuture);
|
||||
Long result = getFutureResult(resultFuture);
|
||||
return result == null ? BackupTransport.TRANSPORT_ERROR : result;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#getNextFullRestoreDataChunk(ParcelFileDescriptor)}
|
||||
*/
|
||||
public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) throws RemoteException {
|
||||
return mTransportBinder.getNextFullRestoreDataChunk(socket);
|
||||
TransportStatusCallback callback = mCallbackPool.acquire();
|
||||
try {
|
||||
mTransportBinder.getNextFullRestoreDataChunk(socket, callback);
|
||||
return callback.getOperationStatus();
|
||||
} finally {
|
||||
mCallbackPool.recycle(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#abortFullRestore()}
|
||||
*/
|
||||
public int abortFullRestore() throws RemoteException {
|
||||
return mTransportBinder.abortFullRestore();
|
||||
TransportStatusCallback callback = mCallbackPool.acquire();
|
||||
try {
|
||||
mTransportBinder.abortFullRestore(callback);
|
||||
return callback.getOperationStatus();
|
||||
} finally {
|
||||
mCallbackPool.recycle(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link IBackupTransport#getTransportFlags()}
|
||||
*/
|
||||
public int getTransportFlags() throws RemoteException {
|
||||
return mTransportBinder.getTransportFlags();
|
||||
AndroidFuture<Integer> resultFuture = new AndroidFuture<>();
|
||||
mTransportBinder.getTransportFlags(resultFuture);
|
||||
Integer result = getFutureResult(resultFuture);
|
||||
return result == null ? BackupTransport.TRANSPORT_ERROR : result;
|
||||
}
|
||||
|
||||
private <T> T getFutureResult(AndroidFuture<T> future) {
|
||||
try {
|
||||
return future.get(600, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
Slog.w(TAG, "Failed to get result from transport:", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class TransportStatusCallbackPool {
|
||||
private static final int MAX_POOL_SIZE = 100;
|
||||
|
||||
private final Object mPoolLock = new Object();
|
||||
private final Queue<TransportStatusCallback> mCallbackPool = new ArrayDeque<>();
|
||||
|
||||
TransportStatusCallback acquire() {
|
||||
synchronized (mPoolLock) {
|
||||
if (mCallbackPool.isEmpty()) {
|
||||
return new TransportStatusCallback();
|
||||
} else {
|
||||
return mCallbackPool.poll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void recycle(TransportStatusCallback callback) {
|
||||
synchronized (mPoolLock) {
|
||||
if (mCallbackPool.size() > MAX_POOL_SIZE) {
|
||||
Slog.d(TAG, "TransportStatusCallback pool size exceeded");
|
||||
return;
|
||||
}
|
||||
|
||||
callback.reset();
|
||||
mCallbackPool.add(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.BackupTransport;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.backup.ITransportStatusCallback;
|
||||
|
||||
public class TransportStatusCallback extends ITransportStatusCallback.Stub {
|
||||
private static final String TAG = "TransportStatusCallback";
|
||||
private static final int TIMEOUT_MILLIS = 600 * 1000; // 10 minutes.
|
||||
private static final int OPERATION_STATUS_DEFAULT = 0;
|
||||
|
||||
private final int mOperationTimeout;
|
||||
|
||||
@GuardedBy("this")
|
||||
private int mOperationStatus = OPERATION_STATUS_DEFAULT;
|
||||
@GuardedBy("this")
|
||||
private boolean mHasCompletedOperation = false;
|
||||
|
||||
public TransportStatusCallback() {
|
||||
mOperationTimeout = TIMEOUT_MILLIS;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
TransportStatusCallback(int operationTimeout) {
|
||||
mOperationTimeout = operationTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onOperationCompleteWithStatus(int status) throws RemoteException {
|
||||
mHasCompletedOperation = true;
|
||||
mOperationStatus = status;
|
||||
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onOperationComplete() throws RemoteException {
|
||||
onOperationCompleteWithStatus(OPERATION_STATUS_DEFAULT);
|
||||
}
|
||||
|
||||
synchronized int getOperationStatus() {
|
||||
if (mHasCompletedOperation) {
|
||||
return mOperationStatus;
|
||||
}
|
||||
|
||||
long timeoutLeft = mOperationTimeout;
|
||||
try {
|
||||
while (!mHasCompletedOperation && timeoutLeft > 0) {
|
||||
long waitStartTime = System.currentTimeMillis();
|
||||
wait(timeoutLeft);
|
||||
if (mHasCompletedOperation) {
|
||||
return mOperationStatus;
|
||||
}
|
||||
timeoutLeft -= System.currentTimeMillis() - waitStartTime;
|
||||
}
|
||||
|
||||
Slog.w(TAG, "Couldn't get operation status from transport");
|
||||
return BackupTransport.TRANSPORT_ERROR;
|
||||
} catch (InterruptedException e) {
|
||||
Slog.w(TAG, "Couldn't get operation status from transport: ", e);
|
||||
return BackupTransport.TRANSPORT_ERROR;
|
||||
} finally {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void reset() {
|
||||
mHasCompletedOperation = false;
|
||||
mOperationStatus = OPERATION_STATUS_DEFAULT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.backup.BackupTransport;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@Presubmit
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TransportStatusCallbackTest {
|
||||
private static final int OPERATION_TIMEOUT_MILLIS = 10;
|
||||
private static final int OPERATION_COMPLETE_STATUS = 123;
|
||||
|
||||
private TransportStatusCallback mTransportStatusCallback;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mTransportStatusCallback = new TransportStatusCallback();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOperationStatus_withPreCompletedOperation_returnsStatus() throws Exception {
|
||||
mTransportStatusCallback.onOperationCompleteWithStatus(OPERATION_COMPLETE_STATUS);
|
||||
|
||||
int result = mTransportStatusCallback.getOperationStatus();
|
||||
|
||||
assertThat(result).isEqualTo(OPERATION_COMPLETE_STATUS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOperationStatus_completeOperation_returnsStatus() throws Exception {
|
||||
Thread thread = new Thread(() -> {
|
||||
int result = mTransportStatusCallback.getOperationStatus();
|
||||
assertThat(result).isEqualTo(OPERATION_COMPLETE_STATUS);
|
||||
});
|
||||
thread.start();
|
||||
|
||||
mTransportStatusCallback.onOperationCompleteWithStatus(OPERATION_COMPLETE_STATUS);
|
||||
|
||||
thread.join();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOperationStatus_operationTimesOut_returnsError() throws Exception {
|
||||
TransportStatusCallback callback = new TransportStatusCallback(OPERATION_TIMEOUT_MILLIS);
|
||||
|
||||
int result = callback.getOperationStatus();
|
||||
|
||||
assertThat(result).isEqualTo(BackupTransport.TRANSPORT_ERROR);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user