blob: 2a8ed40a1e1618294803370e6827296443821130 [file] [log] [blame]
/*
* Copyright 2022 Google LLC
*
* 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.google.android.libraries.mobiledatadownload;
import static com.google.android.libraries.mobiledatadownload.DownloadException.DownloadResultCode.ANDROID_DOWNLOADER_UNKNOWN;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
import androidx.test.core.app.ApplicationProvider;
import com.google.android.libraries.mobiledatadownload.downloader.DownloadConstraints;
import com.google.android.libraries.mobiledatadownload.downloader.DownloadRequest;
import com.google.android.libraries.mobiledatadownload.downloader.FileDownloader;
import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage;
import com.google.android.libraries.mobiledatadownload.file.backends.AndroidFileBackend;
import com.google.android.libraries.mobiledatadownload.internal.logging.LogUtil;
import com.google.android.libraries.mobiledatadownload.monitor.DownloadProgressMonitor;
import com.google.android.libraries.mobiledatadownload.monitor.NetworkUsageMonitor;
import com.google.android.libraries.mobiledatadownload.testing.BlockingFileDownloader;
import com.google.android.libraries.mobiledatadownload.testing.FakeTimeSource;
import com.google.android.libraries.mobiledatadownload.testing.TestFlags;
import com.google.common.base.Optional;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.common.labs.concurrent.LabsFutures;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.shadows.ShadowLog;
@RunWith(RobolectricTestRunner.class)
public final class DownloadFileTest {
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
// 1MB file.
private static final String FILE_URL =
"https://www.gstatic.com/icing/idd/sample_group/sample_file_3_1519240701";
private static final Uri DESTINATION_FILE_URI =
Uri.parse(
"android://com.google.android.libraries.mobiledatadownload/files/datadownload/shared/public/file_1");
private static final Context context = ApplicationProvider.getApplicationContext();
private final TestFlags flags = new TestFlags();
private final FakeTimeSource clock = new FakeTimeSource();
private DownloadProgressMonitor downloadProgressMonitor;
private SynchronousFileStorage fileStorage;
@Mock private SingleFileDownloadListener mockDownloadListener;
@Mock private NetworkUsageMonitor mockNetworkUsageMonitor;
@Mock private FileDownloader mockFileDownloader;
@Mock private DownloadProgressMonitor mockDownloadMonitor;
private BlockingFileDownloader blockingFileDownloader;
private SingleFileDownloadRequest singleFileDownloadRequest;
private MobileDataDownload mobileDataDownload;
@Captor ArgumentCaptor<DownloadListener> downloadListenerCaptor;
@Captor
ArgumentCaptor<com.google.android.libraries.mobiledatadownload.lite.DownloadListener>
liteDownloadListenerCaptor;
@Captor ArgumentCaptor<DownloadRequest> singleFileDownloadRequestCaptor;
ListeningExecutorService controlExecutor =
MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
@Before
public void setUp() {
ShadowLog.setLoggable(LogUtil.TAG, Log.DEBUG);
downloadProgressMonitor = new DownloadProgressMonitor(clock, controlExecutor);
fileStorage =
new SynchronousFileStorage(
/* backends= */ ImmutableList.of(AndroidFileBackend.builder(context).build()),
/* transforms= */ ImmutableList.of(),
/* monitors= */ ImmutableList.of(downloadProgressMonitor));
singleFileDownloadRequest =
SingleFileDownloadRequest.newBuilder()
.setDestinationFileUri(DESTINATION_FILE_URI)
.setUrlToDownload(FILE_URL)
.setDownloadConstraints(DownloadConstraints.NETWORK_CONNECTED)
.setNotificationContentTitle("File url: " + FILE_URL)
.build();
blockingFileDownloader = new BlockingFileDownloader(controlExecutor);
when(mockDownloadListener.onComplete()).thenReturn(Futures.immediateVoidFuture());
when(mockFileDownloader.startDownloading(singleFileDownloadRequestCaptor.capture()))
.thenReturn(Futures.immediateVoidFuture());
}
@After
public void tearDown() {
// Reset state of blockingFileDownloader to prevent deadlocks
blockingFileDownloader.resetState();
}
@Test
public void downloadFile_whenRequestAlreadyMade_dedups() throws Exception {
// Use BlockingFileDownloader to ensure first download is in progress.
mobileDataDownload = getMobileDataDownload(() -> blockingFileDownloader);
ListenableFuture<Void> downloadFuture1 =
mobileDataDownload.downloadFile(singleFileDownloadRequest);
ListenableFuture<Void> downloadFuture2 =
mobileDataDownload.downloadFile(singleFileDownloadRequest);
// Allow blocking download to finish
blockingFileDownloader.finishDownloading();
// Finish future 2 and assert that future 1 has completed as well
downloadFuture2.get();
awaitAllExecutorsIdle();
assertThat(downloadFuture1.isDone()).isTrue();
}
@Test
public void downloadFile_whenRequestAlreadyMadeUsingForegroundService_dedups() throws Exception {
// Use BlockingFileDownloader to ensure first download is in progress.
mobileDataDownload = getMobileDataDownload(() -> blockingFileDownloader);
ListenableFuture<Void> downloadFuture1 =
mobileDataDownload.downloadFileWithForegroundService(singleFileDownloadRequest);
ListenableFuture<Void> downloadFuture2 =
mobileDataDownload.downloadFile(singleFileDownloadRequest);
// Allow blocking download to finish
blockingFileDownloader.finishDownloading();
// Finish future 2 and assert that future 1 has completed as well
downloadFuture2.get();
awaitAllExecutorsIdle();
assertThat(downloadFuture1.isDone()).isTrue();
}
@Test
public void downloadFile_beginsDownload() throws Exception {
mobileDataDownload =
getMobileDataDownload(
() -> mockFileDownloader,
/* foregroundDownloadServiceClassOptional = */ Optional.absent(),
Optional.of(mockDownloadMonitor));
singleFileDownloadRequest =
SingleFileDownloadRequest.newBuilder()
.setDestinationFileUri(DESTINATION_FILE_URI)
.setUrlToDownload(FILE_URL)
.setDownloadConstraints(DownloadConstraints.NETWORK_CONNECTED)
.setListenerOptional(Optional.of(mockDownloadListener))
.build();
ListenableFuture<Void> downloadFuture =
mobileDataDownload.downloadFile(singleFileDownloadRequest);
downloadFuture.get();
awaitAllExecutorsIdle();
// Verify that correct DownloadRequest is sent to underlying FileDownloader
DownloadRequest actualDownloadRequest = singleFileDownloadRequestCaptor.getValue();
assertThat(actualDownloadRequest.fileUri()).isEqualTo(DESTINATION_FILE_URI);
assertThat(actualDownloadRequest.urlToDownload()).isEqualTo(FILE_URL);
assertThat(actualDownloadRequest.downloadConstraints())
.isEqualTo(DownloadConstraints.NETWORK_CONNECTED);
// Verify that downloadMonitor adds the listener
verify(mockDownloadMonitor).addDownloadListener(any(), liteDownloadListenerCaptor.capture());
verify(mockFileDownloader).startDownloading(any());
verify(mockDownloadMonitor).removeDownloadListener(DESTINATION_FILE_URI);
verify(mockDownloadListener).onComplete();
// Ensure that given download listener is the same one passed to download monitor
com.google.android.libraries.mobiledatadownload.lite.DownloadListener capturedDownloadListener =
liteDownloadListenerCaptor.getValue();
DownloadException testException =
DownloadException.builder().setDownloadResultCode(ANDROID_DOWNLOADER_UNKNOWN).build();
capturedDownloadListener.onProgress(10);
capturedDownloadListener.onFailure(testException);
capturedDownloadListener.onPausedForConnectivity();
verify(mockDownloadListener).onProgress(10);
verify(mockDownloadListener).onFailure(testException);
verify(mockDownloadListener).onPausedForConnectivity();
}
@Test
public void download_whenListenerProvided_handlesOnCompleteFailed() throws Exception {
Exception failureException = new Exception("test failure");
when(mockDownloadListener.onComplete())
.thenReturn(Futures.immediateFailedFuture(failureException));
mobileDataDownload =
getMobileDataDownload(
createSuccessfulFileDownloaderSupplier(),
/* foregroundDownloadServiceClassOptional = */ Optional.absent(),
Optional.of(downloadProgressMonitor));
singleFileDownloadRequest =
SingleFileDownloadRequest.newBuilder()
.setDestinationFileUri(DESTINATION_FILE_URI)
.setUrlToDownload(FILE_URL)
.setDownloadConstraints(DownloadConstraints.NETWORK_CONNECTED)
.setListenerOptional(Optional.of(mockDownloadListener))
.build();
mobileDataDownload.downloadFile(singleFileDownloadRequest).get();
awaitAllExecutorsIdle();
// Verify the DownloadListeners onComplete was invoked
verify(mockDownloadListener).onComplete();
}
@Test
public void downloadFile_whenDownloadFails_reportsFailure() throws Exception {
DownloadException downloadException =
DownloadException.builder().setDownloadResultCode(ANDROID_DOWNLOADER_UNKNOWN).build();
mobileDataDownload =
getMobileDataDownload(
createFailingFileDownloaderSupplier(downloadException),
/* foregroundDownloadServiceClassOptional = */ Optional.absent(),
Optional.of(downloadProgressMonitor));
singleFileDownloadRequest =
SingleFileDownloadRequest.newBuilder()
.setDestinationFileUri(DESTINATION_FILE_URI)
.setUrlToDownload(FILE_URL)
.setDownloadConstraints(DownloadConstraints.NETWORK_CONNECTED)
.setListenerOptional(Optional.of(mockDownloadListener))
.build();
ListenableFuture<Void> downloadFuture =
mobileDataDownload.downloadFile(singleFileDownloadRequest);
assertThrows(ExecutionException.class, downloadFuture::get);
DownloadException e = LabsFutures.getFailureCauseAs(downloadFuture, DownloadException.class);
assertThat(e.getDownloadResultCode()).isEqualTo(ANDROID_DOWNLOADER_UNKNOWN);
// Verify that DownloadListener.onFailure was invoked with failure
verify(mockDownloadListener).onFailure(downloadException);
verify(mockDownloadListener, times(0)).onComplete();
}
@Test
public void downloadFile_whenReturnedFutureIsCanceled_cancelsDownload() throws Exception {
// Wrap mock around BlockingFileDownloader to simulate long download
mobileDataDownload = getMobileDataDownload(() -> blockingFileDownloader);
ListenableFuture<Void> downloadFuture =
mobileDataDownload.downloadFile(singleFileDownloadRequest);
// Wait for download to start and confirm download future is still running.
blockingFileDownloader.waitForDownloadStarted();
assertThat(downloadFuture.isDone()).isFalse();
// Cancel download future.
downloadFuture.cancel(true);
// Check that future is now cancelled.
assertThat(downloadFuture.isCancelled()).isTrue();
}
@Test
public void downloadFile_whenMonitorNotProvided_whenDownloadFails_reportsFailure()
throws Exception {
DownloadException downloadException =
DownloadException.builder().setDownloadResultCode(ANDROID_DOWNLOADER_UNKNOWN).build();
mobileDataDownload =
getMobileDataDownload(createFailingFileDownloaderSupplier(downloadException));
singleFileDownloadRequest =
SingleFileDownloadRequest.newBuilder()
.setDestinationFileUri(DESTINATION_FILE_URI)
.setUrlToDownload(FILE_URL)
.setDownloadConstraints(DownloadConstraints.NETWORK_CONNECTED)
.setListenerOptional(Optional.of(mockDownloadListener))
.build();
ListenableFuture<Void> downloadFuture =
mobileDataDownload.downloadFile(singleFileDownloadRequest);
assertThrows(ExecutionException.class, downloadFuture::get);
DownloadException e = LabsFutures.getFailureCauseAs(downloadFuture, DownloadException.class);
assertThat(e.getDownloadResultCode()).isEqualTo(ANDROID_DOWNLOADER_UNKNOWN);
// Verify that DownloadListener.onFailure was invoked with failure
verify(mockDownloadListener).onFailure(downloadException);
verify(mockDownloadListener, times(0)).onComplete();
}
@Test
public void downloadFileWithWithForegroundService_requiresForegroundDownloadService()
throws Exception {
// Create downloader without providing foreground service
mobileDataDownload =
getMobileDataDownload(
() -> mockFileDownloader,
/* foregroundDownloadServiceClassOptional = */ Optional.absent(),
Optional.of(downloadProgressMonitor));
// Without foreground service, download call should fail with IllegalStateException
ListenableFuture<Void> downloadFuture =
mobileDataDownload.downloadFileWithForegroundService(singleFileDownloadRequest);
ExecutionException e = assertThrows(ExecutionException.class, downloadFuture::get);
assertThat(e).hasCauseThat().isInstanceOf(IllegalStateException.class);
// Verify that underlying download is not started
verify(mockFileDownloader, times(0)).startDownloading(any());
}
@Test
public void downloadFileWithForegroundService_requiresDownloadMonitor() throws Exception {
// Create downloader without providing DownloadMonitor
mobileDataDownload =
getMobileDataDownload(
() -> mockFileDownloader,
Optional.of(this.getClass()),
/* downloadProgressMonitorOptional = */ Optional.absent());
// Without monitor, download call should fail with IllegalStateException
ListenableFuture<Void> downloadFuture =
mobileDataDownload.downloadFileWithForegroundService(singleFileDownloadRequest);
ExecutionException e = assertThrows(ExecutionException.class, downloadFuture::get);
assertThat(e).hasCauseThat().isInstanceOf(IllegalStateException.class);
// Verify that underlying download is not started
verify(mockFileDownloader, times(0)).startDownloading(any());
}
@Test
public void downloadFileWithForegroundService_whenRequestAlreadyMade_dedups() throws Exception {
// Use BlockingFileDownloader to control when the download will finish.
mobileDataDownload = getMobileDataDownload(() -> blockingFileDownloader);
ListenableFuture<Void> downloadFuture1 =
mobileDataDownload.downloadFileWithForegroundService(singleFileDownloadRequest);
ListenableFuture<Void> downloadFuture2 =
mobileDataDownload.downloadFileWithForegroundService(singleFileDownloadRequest);
// Now we let the 2 futures downloadFuture1 downloadFuture2 to run by opening the latch.
blockingFileDownloader.finishDownloading();
// Now finish future 2, future 1 should finish too and the cache clears the future.
downloadFuture2.get();
awaitAllExecutorsIdle();
assertThat(downloadFuture1.isDone()).isTrue();
}
@Test
public void
downloadFileWithForegroundService_whenRequestAlreadyMadeWithoutForegroundService_dedups()
throws Exception {
// Use BlockingFileDownloader to control when the download will finish.
mobileDataDownload =
getMobileDataDownload(
() -> blockingFileDownloader,
Optional.of(this.getClass()),
Optional.of(downloadProgressMonitor));
ListenableFuture<Void> downloadFuture1 =
mobileDataDownload.downloadFile(singleFileDownloadRequest);
ListenableFuture<Void> downloadFuture2 =
mobileDataDownload.downloadFileWithForegroundService(singleFileDownloadRequest);
// Now we let the 2 futures downloadFuture1 downloadFuture2 to run by opening the latch.
blockingFileDownloader.finishDownloading();
// Now finish future 2, future 1 should finish too and the cache clears the future.
downloadFuture2.get();
awaitAllExecutorsIdle();
assertThat(downloadFuture1.isDone()).isTrue();
}
@Test
public void downloadFileWithForegroundService() throws Exception {
when(mockFileDownloader.startDownloading(singleFileDownloadRequestCaptor.capture()))
.thenReturn(Futures.immediateVoidFuture());
mobileDataDownload =
getMobileDataDownload(
() -> mockFileDownloader,
Optional.of(this.getClass()),
Optional.of(mockDownloadMonitor));
singleFileDownloadRequest =
SingleFileDownloadRequest.newBuilder()
.setDestinationFileUri(DESTINATION_FILE_URI)
.setUrlToDownload(FILE_URL)
.setDownloadConstraints(DownloadConstraints.NETWORK_CONNECTED)
.setNotificationContentTitle("File url: " + FILE_URL)
.setListenerOptional(Optional.of(mockDownloadListener))
.build();
ListenableFuture<Void> downloadFuture =
mobileDataDownload.downloadFileWithForegroundService(singleFileDownloadRequest);
downloadFuture.get();
awaitAllExecutorsIdle();
// Verify that the correct DownloadRequest is sent to underderlying FileDownloader.
DownloadRequest actualDownloadRequest = singleFileDownloadRequestCaptor.getValue();
assertThat(actualDownloadRequest.fileUri()).isEqualTo(DESTINATION_FILE_URI);
assertThat(actualDownloadRequest.urlToDownload()).isEqualTo(FILE_URL);
assertThat(actualDownloadRequest.downloadConstraints())
.isEqualTo(DownloadConstraints.NETWORK_CONNECTED);
// Verify that downloadMonitor will add a DownloadListener.
verify(mockDownloadMonitor).addDownloadListener(any(), liteDownloadListenerCaptor.capture());
verify(mockFileDownloader).startDownloading(any());
verify(mockDownloadMonitor).removeDownloadListener(DESTINATION_FILE_URI);
verify(mockDownloadListener).onComplete();
com.google.android.libraries.mobiledatadownload.lite.DownloadListener capturedListener =
liteDownloadListenerCaptor.getValue();
// Now simulate other DownloadListener's callbacks:
capturedListener.onProgress(10);
capturedListener.onPausedForConnectivity();
DownloadException downloadException =
DownloadException.builder().setDownloadResultCode(ANDROID_DOWNLOADER_UNKNOWN).build();
capturedListener.onFailure(downloadException);
awaitAllExecutorsIdle();
verify(mockDownloadListener).onProgress(10);
verify(mockDownloadListener).onPausedForConnectivity();
verify(mockDownloadListener).onFailure(downloadException);
}
@Test
public void downloadFileWithForegroundService_clientOnCompleteFailed() throws Exception {
Exception failureException = new Exception("test failure");
when(mockFileDownloader.startDownloading(singleFileDownloadRequestCaptor.capture()))
.thenReturn(Futures.immediateVoidFuture());
mobileDataDownload =
getMobileDataDownload(
() -> mockFileDownloader,
Optional.of(this.getClass()),
Optional.of(downloadProgressMonitor));
// Client's provided DownloadListener.onComplete failed.
when(mockDownloadListener.onComplete())
.thenReturn(Futures.immediateFailedFuture(failureException));
singleFileDownloadRequest =
SingleFileDownloadRequest.newBuilder()
.setDestinationFileUri(DESTINATION_FILE_URI)
.setUrlToDownload(FILE_URL)
.setDownloadConstraints(DownloadConstraints.NETWORK_CONNECTED)
.setNotificationContentTitle("File url: " + FILE_URL)
.setListenerOptional(Optional.of(mockDownloadListener))
.build();
ListenableFuture<Void> downloadFuture =
mobileDataDownload.downloadFileWithForegroundService(singleFileDownloadRequest);
downloadFuture.get();
awaitAllExecutorsIdle();
// Verify that the correct DownloadRequest is sent to underderlying FileDownloader.
DownloadRequest actualDownloadRequest = singleFileDownloadRequestCaptor.getValue();
assertThat(actualDownloadRequest.fileUri()).isEqualTo(DESTINATION_FILE_URI);
assertThat(actualDownloadRequest.urlToDownload()).isEqualTo(FILE_URL);
assertThat(actualDownloadRequest.downloadConstraints())
.isEqualTo(DownloadConstraints.NETWORK_CONNECTED);
verify(mockFileDownloader).startDownloading(any());
verify(mockDownloadListener).onComplete();
}
@Test
public void downloadFileWithForegroundService_failure() throws Exception {
DownloadException downloadException =
DownloadException.builder().setDownloadResultCode(ANDROID_DOWNLOADER_UNKNOWN).build();
when(mockFileDownloader.startDownloading(singleFileDownloadRequestCaptor.capture()))
.thenReturn(Futures.immediateFailedFuture(downloadException));
mobileDataDownload =
getMobileDataDownload(
() -> mockFileDownloader,
Optional.of(this.getClass()),
Optional.of(downloadProgressMonitor));
singleFileDownloadRequest =
SingleFileDownloadRequest.newBuilder()
.setDestinationFileUri(DESTINATION_FILE_URI)
.setUrlToDownload(FILE_URL)
.setDownloadConstraints(DownloadConstraints.NETWORK_CONNECTED)
.setNotificationContentTitle("File url: " + FILE_URL)
.setListenerOptional(Optional.of(mockDownloadListener))
.build();
ListenableFuture<Void> downloadFuture =
mobileDataDownload.downloadFileWithForegroundService(singleFileDownloadRequest);
assertThrows(ExecutionException.class, downloadFuture::get);
DownloadException e = LabsFutures.getFailureCauseAs(downloadFuture, DownloadException.class);
assertThat(e.getDownloadResultCode()).isEqualTo(ANDROID_DOWNLOADER_UNKNOWN);
awaitAllExecutorsIdle();
// Verify that the correct DownloadRequest is sent to underderlying FileDownloader.
DownloadRequest actualDownloadRequest = singleFileDownloadRequestCaptor.getValue();
assertThat(actualDownloadRequest.fileUri()).isEqualTo(DESTINATION_FILE_URI);
assertThat(actualDownloadRequest.urlToDownload()).isEqualTo(FILE_URL);
assertThat(actualDownloadRequest.downloadConstraints())
.isEqualTo(DownloadConstraints.NETWORK_CONNECTED);
// Since the download failed, onComplete will not be called but onFailure.
verify(mockDownloadListener, times(0)).onComplete();
verify(mockDownloadListener).onFailure(downloadException);
}
@Test
public void cancelDownloadFileWithForegroundService() throws Exception {
// Use BlockingFileDownloader to control when the download will finish.
mobileDataDownload = getMobileDataDownload(() -> blockingFileDownloader);
ListenableFuture<Void> downloadFuture =
mobileDataDownload.downloadFileWithForegroundService(singleFileDownloadRequest);
mobileDataDownload.cancelForegroundDownload(DESTINATION_FILE_URI.toString());
awaitAllExecutorsIdle();
assertTrue(downloadFuture.isCancelled());
}
@Test
public void cancelListenableFuture() throws Exception {
// Use BlockingFileDownloader to control when the download will finish.
mobileDataDownload = getMobileDataDownload(() -> blockingFileDownloader);
ListenableFuture<Void> downloadFuture =
mobileDataDownload.downloadFileWithForegroundService(singleFileDownloadRequest);
// Wait for download to start and confirm download future is still running.
blockingFileDownloader.waitForDownloadStarted();
assertThat(downloadFuture.isDone()).isFalse();
// Cancel download future.
downloadFuture.cancel(true);
// Check that future is now cancelled.
assertThat(downloadFuture.isCancelled()).isTrue();
}
private Supplier<FileDownloader> createFailingFileDownloaderSupplier(Throwable throwable) {
return Suppliers.ofInstance(
new FileDownloader() {
@Override
public ListenableFuture<Void> startDownloading(DownloadRequest request) {
return Futures.immediateFailedFuture(throwable);
}
});
}
private Supplier<FileDownloader> createSuccessfulFileDownloaderSupplier() {
return Suppliers.ofInstance(
new FileDownloader() {
@Override
public ListenableFuture<Void> startDownloading(DownloadRequest request) {
return Futures.immediateVoidFuture();
}
});
}
private MobileDataDownload getMobileDataDownload(
Supplier<FileDownloader> fileDownloaderSupplier) {
return getMobileDataDownload(
fileDownloaderSupplier, Optional.of(this.getClass()), Optional.of(downloadProgressMonitor));
}
private MobileDataDownload getMobileDataDownload(
Supplier<FileDownloader> fileDownloaderSupplier,
Optional<Class<?>> foregroundDownloadServiceClassOptional,
Optional<DownloadProgressMonitor> downloadProgressMonitorOptional) {
return MobileDataDownloadBuilder.newBuilder()
.setContext(context)
.setControlExecutor(controlExecutor)
.setFileDownloaderSupplier(fileDownloaderSupplier)
.setFileStorage(fileStorage)
.setDownloadMonitorOptional(downloadProgressMonitorOptional)
.setNetworkUsageMonitor(mockNetworkUsageMonitor)
.setForegroundDownloadServiceOptional(foregroundDownloadServiceClassOptional)
.setFlagsOptional(Optional.of(flags))
.build();
}
/** Waits long enough for async operations to finish running. */
// TODO(b/217551873): investigate ways to make this more robust
private static void awaitAllExecutorsIdle() throws Exception {
Thread.sleep(/* millis= */ 100);
}
}