summaryrefslogtreecommitdiff
path: root/javatests/com/google/android/libraries/mobiledatadownload/DownloadFileGroupIntegrationTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'javatests/com/google/android/libraries/mobiledatadownload/DownloadFileGroupIntegrationTest.java')
-rw-r--r--javatests/com/google/android/libraries/mobiledatadownload/DownloadFileGroupIntegrationTest.java559
1 files changed, 355 insertions, 204 deletions
diff --git a/javatests/com/google/android/libraries/mobiledatadownload/DownloadFileGroupIntegrationTest.java b/javatests/com/google/android/libraries/mobiledatadownload/DownloadFileGroupIntegrationTest.java
index c5b3239..818b2e4 100644
--- a/javatests/com/google/android/libraries/mobiledatadownload/DownloadFileGroupIntegrationTest.java
+++ b/javatests/com/google/android/libraries/mobiledatadownload/DownloadFileGroupIntegrationTest.java
@@ -20,42 +20,51 @@ import static com.google.android.libraries.mobiledatadownload.TestFileGroupPopul
import static com.google.android.libraries.mobiledatadownload.TestFileGroupPopulator.FILE_ID;
import static com.google.android.libraries.mobiledatadownload.TestFileGroupPopulator.FILE_SIZE;
import static com.google.android.libraries.mobiledatadownload.TestFileGroupPopulator.FILE_URL;
+import static com.google.android.libraries.mobiledatadownload.testing.MddTestDependencies.DownloaderConfigurationType;
+import static com.google.android.libraries.mobiledatadownload.testing.MddTestDependencies.ExecutorType;
import static com.google.common.truth.Truth.assertThat;
+import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.fail;
+import android.accounts.Account;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import com.google.android.libraries.mobiledatadownload.downloader.DownloadRequest;
+import com.google.android.libraries.mobiledatadownload.account.AccountUtil;
import com.google.android.libraries.mobiledatadownload.downloader.FileDownloader;
-import com.google.android.libraries.mobiledatadownload.downloader.offroad.dagger.downloader2.BaseFileDownloaderModule;
import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage;
import com.google.android.libraries.mobiledatadownload.file.backends.AndroidFileBackend;
-import com.google.android.libraries.mobiledatadownload.file.integration.downloader.SharedPreferencesDownloadMetadata;
+import com.google.android.libraries.mobiledatadownload.file.backends.JavaFileBackend;
import com.google.android.libraries.mobiledatadownload.file.transforms.CompressTransform;
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.MddTestDependencies;
+import com.google.android.libraries.mobiledatadownload.testing.TestFileDownloader;
import com.google.android.libraries.mobiledatadownload.testing.TestFlags;
import com.google.common.base.Optional;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
-import com.google.common.util.concurrent.FutureCallback;
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.ListeningScheduledExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.mobiledatadownload.ClientConfigProto.ClientFile;
import com.google.mobiledatadownload.ClientConfigProto.ClientFileGroup;
+import com.google.mobiledatadownload.DownloadConfigProto.DataFile;
import com.google.mobiledatadownload.DownloadConfigProto.DataFileGroup;
import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions.DeviceNetworkPolicy;
+import com.google.mobiledatadownload.TransformProto;
+import com.google.mobiledatadownload.TransformProto.Transform;
+import com.google.mobiledatadownload.TransformProto.Transforms;
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -64,19 +73,22 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-@RunWith(AndroidJUnit4.class)
+/**
+ * Integration Tests that relate to {@link MobileDataDownload#downloadFileGroup}.
+ *
+ * <p>NOTE: Any tests related to cancellation should be added to {@link
+ * DownloadFileGroupCancellationIntegrationTest} instead.
+ */
+@RunWith(TestParameterInjector.class)
public class DownloadFileGroupIntegrationTest {
private static final String TAG = "DownloadFileGroupIntegrationTest";
- private static final int MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS = 300;
+ private static final int MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS = 60;
+ private static final int MAX_MULTI_MDD_API_WAIT_TIME_SECS = 120;
+ private static final long MAX_MDD_API_WAIT_TIME_SECS = 5L;
- // Note: Control Executor must not be a single thread executor.
- private static final ListeningExecutorService CONTROL_EXECUTOR =
- MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
- private static final ScheduledExecutorService DOWNLOAD_EXECUTOR =
- Executors.newScheduledThreadPool(2);
- private static final ListeningExecutorService listeningExecutorService =
- MoreExecutors.listeningDecorator(DOWNLOAD_EXECUTOR);
+ private static final ListeningScheduledExecutorService DOWNLOAD_EXECUTOR =
+ MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(4));
private static final String FILE_GROUP_NAME_INSECURE_URL = "test-group-insecure-url";
private static final String FILE_GROUP_NAME_MULTIPLE_FILES = "test-group-multiple-files";
@@ -88,6 +100,24 @@ public class DownloadFileGroupIntegrationTest {
private static final String FILE_NOT_EXIST_URL =
"https://www.gstatic.com/icing/idd/notexist/file.txt";
+ private static final String TEST_DATA_RELATIVE_PATH =
+ "third_party/java_src/android_libs/mobiledatadownload/javatests/com/google/android/libraries/mobiledatadownload/testdata/";
+
+ private static final String TEST_DATA_URL = "https://test.url/full_file.txt";
+ private static final String TEST_DATA_CHECKSUM = "0c4f1e55c4ec28d0305c5cfde8610b7e6e9f7d9a";
+ private static final int TEST_DATA_BYTE_SIZE = 110;
+
+ private static final String TEST_DATA_COMPRESS_URL = "https://test.url/full_file.zlib";
+ private static final String TEST_DATA_COMPRESS_CHECKSUM =
+ "cbffcf480fd52a3c6bf9d21206d36f0a714bb97a";
+ private static final int TEST_DATA_COMPRESS_BYTE_SIZE = 92;
+
+ private static final String VARIANT_1 = "test-variant-1";
+ private static final String VARIANT_2 = "test-variant-2";
+
+ private static final Account ACCOUNT_1 = AccountUtil.create("account-name-1", "account-type");
+ private static final Account ACCOUNT_2 = AccountUtil.create("account-name-2", "account-type");
+
private static final Context context = ApplicationProvider.getApplicationContext();
@Mock private TaskScheduler mockTaskScheduler;
@@ -95,81 +125,111 @@ public class DownloadFileGroupIntegrationTest {
@Mock private DownloadProgressMonitor mockDownloadProgressMonitor;
private SynchronousFileStorage fileStorage;
+ private ListeningExecutorService controlExecutor;
private final TestFlags flags = new TestFlags();
- @Rule public final MockitoRule mocks = MockitoJUnit.rule();
+ @Rule(order = 1)
+ public final MockitoRule mocks = MockitoJUnit.rule();
- /* Differentiates between Downloader libraries for shared test method assertions. */
- private enum DownloaderVersion {
- V2
- }
+ @TestParameter ExecutorType controlExecutorType;
@Before
public void setUp() throws Exception {
fileStorage =
new SynchronousFileStorage(
- /* backends= */ ImmutableList.of(AndroidFileBackend.builder(context).build()),
+ /* backends= */ ImmutableList.of(
+ AndroidFileBackend.builder(context).build(), new JavaFileBackend()),
/* transforms= */ ImmutableList.of(new CompressTransform()),
/* monitors= */ ImmutableList.of(mockNetworkUsageMonitor, mockDownloadProgressMonitor));
- }
- @Test
- public void downloadAndRead_downloader2() throws Exception {
- Supplier<FileDownloader> fileDownloaderSupplier =
- () ->
- BaseFileDownloaderModule.createOffroad2FileDownloader(
- context,
- DOWNLOAD_EXECUTOR,
- CONTROL_EXECUTOR,
- fileStorage,
- new SharedPreferencesDownloadMetadata(
- context.getSharedPreferences("downloadmetadata", 0), listeningExecutorService),
- Optional.of(mockDownloadProgressMonitor),
- /* urlEngineOptional= */ Optional.absent(),
- /* exceptionHandlerOptional= */ Optional.absent(),
- /* authTokenProviderOptional= */ Optional.absent(),
- /* trafficTag= */ Optional.absent(),
- flags);
-
- testDownloadAndRead(fileDownloaderSupplier, DownloaderVersion.V2);
+ controlExecutor = controlExecutorType.executor();
}
@Test
- public void downloadFailed_downloader2() throws Exception {
- Supplier<FileDownloader> fileDownloaderSupplier =
- () ->
- BaseFileDownloaderModule.createOffroad2FileDownloader(
- context,
- DOWNLOAD_EXECUTOR,
- CONTROL_EXECUTOR,
- fileStorage,
- new SharedPreferencesDownloadMetadata(
- context.getSharedPreferences("downloadmetadata", 0), listeningExecutorService),
- Optional.of(mockDownloadProgressMonitor),
- /* urlEngineOptional= */ Optional.absent(),
- /* exceptionHandlerOptional= */ Optional.absent(),
- /* authTokenProviderOptional= */ Optional.absent(),
- /* trafficTag= */ Optional.absent(),
- flags);
-
- testDownloadFailed(fileDownloaderSupplier, DownloaderVersion.V2);
+ public void downloadAndRead(
+ @TestParameter DownloaderConfigurationType downloaderConfigurationType) throws Exception {
+ Optional<String> instanceId = Optional.of(MddTestDependencies.randomInstanceId());
+ TestFileGroupPopulator testFileGroupPopulator = new TestFileGroupPopulator(context);
+ MobileDataDownload mobileDataDownload =
+ builderForTest()
+ .setInstanceIdOptional(instanceId)
+ .setFileDownloaderSupplier(
+ downloaderConfigurationType.fileDownloaderSupplier(
+ context,
+ controlExecutor,
+ DOWNLOAD_EXECUTOR,
+ fileStorage,
+ flags,
+ Optional.of(mockDownloadProgressMonitor),
+ instanceId))
+ .addFileGroupPopulator(testFileGroupPopulator)
+ .build();
+
+ testFileGroupPopulator
+ .refreshFileGroups(mobileDataDownload)
+ .get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS);
+
+ mobileDataDownload
+ .downloadFileGroup(
+ DownloadFileGroupRequest.newBuilder()
+ .setGroupName(FILE_GROUP_NAME)
+ .setListenerOptional(
+ Optional.of(
+ new DownloadListener() {
+ @Override
+ public void onProgress(long currentSize) {
+ Log.i(TAG, "onProgress " + currentSize);
+ }
+
+ @Override
+ public void onComplete(ClientFileGroup clientFileGroup) {
+ Log.i(TAG, "onComplete " + clientFileGroup.getGroupName());
+ }
+ }))
+ .build())
+ .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS);
+
+ ClientFileGroup clientFileGroup =
+ mobileDataDownload
+ .getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME).build())
+ .get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS);
+
+ assertThat(clientFileGroup).isNotNull();
+ assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME);
+ assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
+
+ ClientFile clientFile = clientFileGroup.getFileList().get(0);
+ assertThat(clientFile.getFileId()).isEqualTo(FILE_ID);
+ Uri androidUri = Uri.parse(clientFile.getFileUri());
+ assertThat(fileStorage.fileSize(androidUri)).isEqualTo(FILE_SIZE);
+
+ mobileDataDownload.clear().get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS);
+
+ switch (downloaderConfigurationType) {
+ case V2_PLATFORM:
+ // No-op
+ }
}
- private void testDownloadFailed(
- Supplier<FileDownloader> fileDownloaderSupplier, DownloaderVersion version) throws Exception {
+ @Test
+ public void downloadFailed() throws Exception {
+ // NOTE: The test failures here are not network stack dependent, so there's
+ // no need to parameterize this test for different network stacks.
+ Optional<String> instanceId = Optional.of(MddTestDependencies.randomInstanceId());
MobileDataDownload mobileDataDownload =
- MobileDataDownloadBuilder.newBuilder()
- .setContext(context)
- .setControlExecutor(CONTROL_EXECUTOR)
- .setFileDownloaderSupplier(fileDownloaderSupplier)
- .setTaskScheduler(Optional.of(mockTaskScheduler))
- .setDeltaDecoderOptional(Optional.absent())
- .setFileStorage(fileStorage)
- .setNetworkUsageMonitor(mockNetworkUsageMonitor)
- .setDownloadMonitorOptional(Optional.of(mockDownloadProgressMonitor))
- .setFlagsOptional(Optional.of(flags))
+ builderForTest()
+ .setInstanceIdOptional(instanceId)
+ .setFileDownloaderSupplier(
+ DownloaderConfigurationType.V2_PLATFORM.fileDownloaderSupplier(
+ context,
+ controlExecutor,
+ DOWNLOAD_EXECUTOR,
+ fileStorage,
+ flags,
+ Optional.of(mockDownloadProgressMonitor),
+ instanceId))
.build();
// The data file group has a file with insecure url.
@@ -200,7 +260,7 @@ public class DownloadFileGroupIntegrationTest {
mobileDataDownload
.addFileGroup(
AddFileGroupRequest.newBuilder().setDataFileGroup(groupWithInsecureUrl).build())
- .get())
+ .get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS))
.isTrue();
assertThat(
@@ -209,7 +269,7 @@ public class DownloadFileGroupIntegrationTest {
AddFileGroupRequest.newBuilder()
.setDataFileGroup(groupWithMultipleFiles)
.build())
- .get())
+ .get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS))
.isTrue();
ExecutionException exception =
@@ -221,7 +281,7 @@ public class DownloadFileGroupIntegrationTest {
DownloadFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_INSECURE_URL)
.build())
- .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, TimeUnit.SECONDS));
+ .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS));
assertThat(exception).hasCauseThat().isInstanceOf(AggregateException.class);
AggregateException cause = (AggregateException) exception.getCause();
assertThat(cause).isNotNull();
@@ -239,173 +299,264 @@ public class DownloadFileGroupIntegrationTest {
DownloadFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_MULTIPLE_FILES)
.build())
- .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, TimeUnit.SECONDS));
+ .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS));
assertThat(exception2).hasCauseThat().isInstanceOf(AggregateException.class);
AggregateException cause2 = (AggregateException) exception2.getCause();
assertThat(cause2).isNotNull();
ImmutableList<Throwable> failures2 = cause2.getFailures();
assertThat(failures2).hasSize(2);
assertThat(failures2.get(0)).isInstanceOf(DownloadException.class);
- switch (version) {
- case V2:
- assertThat(failures2.get(0))
- .hasCauseThat()
- .hasMessageThat()
- .containsMatch("httpStatusCode=404");
- break;
- }
+ assertThat(failures2.get(0))
+ .hasCauseThat()
+ .hasMessageThat()
+ .containsMatch("httpStatusCode=404");
assertThat(failures2.get(1)).isInstanceOf(DownloadException.class);
assertThat(failures2.get(1)).hasMessageThat().contains("INSECURE_URL_ERROR");
- switch (version) {
- case V2:
- // No-op
- }
+ AggregateException exception3 =
+ assertThrows(
+ AggregateException.class,
+ () -> {
+ try {
+ ListenableFuture<ClientFileGroup> downloadFuture1 =
+ mobileDataDownload.downloadFileGroup(
+ DownloadFileGroupRequest.newBuilder()
+ .setGroupName(FILE_GROUP_NAME_MULTIPLE_FILES)
+ .build());
+ ListenableFuture<ClientFileGroup> downloadFuture2 =
+ mobileDataDownload.downloadFileGroup(
+ DownloadFileGroupRequest.newBuilder()
+ .setGroupName(FILE_GROUP_NAME_INSECURE_URL)
+ .build());
+
+ Futures.successfulAsList(downloadFuture1, downloadFuture2)
+ .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS);
+
+ AggregateException.throwIfFailed(
+ ImmutableList.of(downloadFuture1, downloadFuture2),
+ "Expected download failures");
+ } catch (ExecutionException e) {
+ throw e;
+ }
+ });
+ assertThat(exception3.getFailures()).hasSize(2);
}
- private void testDownloadAndRead(
- Supplier<FileDownloader> fileDownloaderSupplier, DownloaderVersion version) throws Exception {
- TestFileGroupPopulator testFileGroupPopulator = new TestFileGroupPopulator(context);
+ @Test
+ public void removePartialDownloadThenDownloadAgain(
+ @TestParameter DownloaderConfigurationType downloaderConfigurationType) throws Exception {
+ Optional<String> instanceId = Optional.of(MddTestDependencies.randomInstanceId());
+
+ Supplier<FileDownloader> fileDownloaderSupplier =
+ downloaderConfigurationType.fileDownloaderSupplier(
+ context,
+ controlExecutor,
+ DOWNLOAD_EXECUTOR,
+ fileStorage,
+ flags,
+ Optional.of(mockDownloadProgressMonitor),
+ instanceId);
+ BlockingFileDownloader blockingFileDownloader =
+ new BlockingFileDownloader(DOWNLOAD_EXECUTOR, fileDownloaderSupplier.get());
+
MobileDataDownload mobileDataDownload =
- MobileDataDownloadBuilder.newBuilder()
- .setContext(context)
- .setControlExecutor(CONTROL_EXECUTOR)
- .setFileDownloaderSupplier(fileDownloaderSupplier)
- .addFileGroupPopulator(testFileGroupPopulator)
- .setTaskScheduler(Optional.of(mockTaskScheduler))
- .setDeltaDecoderOptional(Optional.absent())
- .setFileStorage(fileStorage)
- .setNetworkUsageMonitor(mockNetworkUsageMonitor)
- .setDownloadMonitorOptional(Optional.of(mockDownloadProgressMonitor))
- .setFlagsOptional(Optional.of(flags))
+ builderForTest()
+ .setInstanceIdOptional(instanceId)
+ .setFileDownloaderSupplier(() -> blockingFileDownloader)
.build();
- testFileGroupPopulator.refreshFileGroups(mobileDataDownload).get();
- mobileDataDownload
- .downloadFileGroup(
- DownloadFileGroupRequest.newBuilder()
- .setGroupName(FILE_GROUP_NAME)
- .setListenerOptional(
- Optional.of(
- new DownloadListener() {
- @Override
- public void onProgress(long currentSize) {
- Log.i(TAG, "onProgress " + currentSize);
- }
+ mobileDataDownload.clear().get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS);
- @Override
- public void onComplete(ClientFileGroup clientFileGroup) {
- Log.i(TAG, "onComplete " + clientFileGroup.getGroupName());
- }
- }))
- .build())
- .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, TimeUnit.SECONDS);
+ // Add the filegroup, start downloading, then cancel while in progress.
+ TestFileGroupPopulator testFileGroupPopulator = new TestFileGroupPopulator(context);
+ testFileGroupPopulator
+ .refreshFileGroups(mobileDataDownload)
+ .get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS);
- String debugString = mobileDataDownload.getDebugInfoAsString();
- Log.i(TAG, "MDD Lib dump:");
- for (String line : debugString.split("\n", -1)) {
- Log.i(TAG, line);
- }
+ ListenableFuture<ClientFileGroup> downloadFuture =
+ mobileDataDownload.downloadFileGroup(
+ DownloadFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME).build());
+
+ blockingFileDownloader.finishDownloading(); // Unblocks blockingFileDownloader
+ blockingFileDownloader.waitForDelegateStarted(); // Waits until offroadDownloader starts
+
+ // NOTE: add a little wait to allow Downloader's listeners to run.
+ Thread.sleep(/* millis= */ 200);
+
+ downloadFuture.cancel(true /* may interrupt */);
+
+ // NOTE: add a little wait to allow Downloader's listeners to run.
+ Thread.sleep(/* millis= */ 200);
+
+ // Remove the filegroup.
+ ListenableFuture<Boolean> removeFuture =
+ mobileDataDownload.removeFileGroup(
+ RemoveFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME).build());
+ removeFuture.get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS);
+
+ // Add then try to download again.
+ blockingFileDownloader.resetState();
+ blockingFileDownloader.finishDownloading(); // Unblocks blockingFileDownloader
+
+ testFileGroupPopulator
+ .refreshFileGroups(mobileDataDownload)
+ .get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS);
+ downloadFuture =
+ mobileDataDownload.downloadFileGroup(
+ DownloadFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME).build());
+
+ downloadFuture.get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS);
+
+ // The file should have downloaded as expected.
ClientFileGroup clientFileGroup =
mobileDataDownload
.getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME).build())
- .get();
+ .get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS);
assertThat(clientFileGroup).isNotNull();
- assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME);
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
-
- ClientFile clientFile = clientFileGroup.getFileList().get(0);
- assertThat(clientFile.getFileId()).isEqualTo(FILE_ID);
- Uri androidUri = Uri.parse(clientFile.getFileUri());
+ Uri androidUri = Uri.parse(clientFileGroup.getFileList().get(0).getFileUri());
assertThat(fileStorage.fileSize(androidUri)).isEqualTo(FILE_SIZE);
+ }
+
+ @Test
+ public void downloadDifferentGroupsWithSameFileTest() throws Exception {
+ Optional<String> instanceId = Optional.of(MddTestDependencies.randomInstanceId());
+ MobileDataDownload mobileDataDownload =
+ builderForTest()
+ .setInstanceIdOptional(instanceId)
+ .setFileDownloaderSupplier(
+ () ->
+ new TestFileDownloader(TEST_DATA_RELATIVE_PATH, fileStorage, DOWNLOAD_EXECUTOR))
+ .build();
+
+ DataFile.Builder dataFileBuilder =
+ DataFile.newBuilder()
+ .setUrlToDownload(TEST_DATA_URL)
+ .setChecksum(TEST_DATA_CHECKSUM)
+ .setByteSize(TEST_DATA_BYTE_SIZE);
+ DataFileGroup.Builder groupBuilder = DataFileGroup.newBuilder();
+
+ // Add all groups concurrently
+ ArrayList<ListenableFuture<Boolean>> addFutures = new ArrayList<>();
+ for (int i = 0; i < 50; i++) {
+ String groupName = String.format("group%d", i);
+ String fileId = String.format("group%d_file", i);
+
+ DataFile file = dataFileBuilder.setFileId(fileId).build();
+ DataFileGroup group =
+ DataFileGroup.newBuilder().setGroupName(groupName).addFile(file).build();
+
+ addFutures.add(
+ mobileDataDownload.addFileGroup(
+ AddFileGroupRequest.newBuilder().setDataFileGroup(group).build()));
+ }
+ Futures.allAsList(addFutures).get(MAX_MULTI_MDD_API_WAIT_TIME_SECS, SECONDS);
- mobileDataDownload.clear().get();
+ // Start all downloads concurrently
+ ArrayList<ListenableFuture<ClientFileGroup>> downloadFutures = new ArrayList<>();
+ for (int i = 0; i < 50; i++) {
+ String groupName = String.format("group%d", i);
- switch (version) {
- case V2:
- // No-op
+ downloadFutures.add(
+ mobileDataDownload.downloadFileGroup(
+ DownloadFileGroupRequest.newBuilder().setGroupName(groupName).build()));
}
+ List<ClientFileGroup> groups =
+ Futures.allAsList(downloadFutures).get(MAX_MULTI_MDD_API_WAIT_TIME_SECS, SECONDS);
+
+ assertThat(groups).doesNotContain(null);
}
@Test
- public void cancelDownload() throws Exception {
- // In this test we will start a download and make sure that calling cancel on the returned
- // future will cancel the download.
- // We create a BlockingFileDownloader that allows the download to be blocked indefinitely.
- // We also provide a delegate FileDownloader that attaches a FutureCallback to the internal
- // download future and fail if the future is not cancelled.
- BlockingFileDownloader blockingFileDownloader =
- new BlockingFileDownloader(
- listeningExecutorService,
- new FileDownloader() {
- @Override
- public ListenableFuture<Void> startDownloading(DownloadRequest downloadRequest) {
- ListenableFuture<Void> downloadTaskFuture = Futures.immediateVoidFuture();
- Futures.addCallback(
- downloadTaskFuture,
- new FutureCallback<Void>() {
- @Override
- public void onSuccess(Void result) {
- // Should not get here since we will cancel the future.
- fail();
- }
-
- @Override
- public void onFailure(Throwable t) {
- assertThat(downloadTaskFuture.isCancelled()).isTrue();
-
- Log.i(TAG, "downloadTask is cancelled!");
- }
- },
- listeningExecutorService);
- return downloadTaskFuture;
- }
- });
- Supplier<FileDownloader> neverFinishDownloader = () -> blockingFileDownloader;
+ public void concurrentDownloads_withSameFile_withDifferentDownloadTransforms_completes(
+ @TestParameter boolean enableDedupByFileKey) throws Exception {
+ flags.enableFileDownloadDedupByFileKey = Optional.of(enableDedupByFileKey);
- // Use never finish downloader to test whether the cancellation on the downloadFuture would
- // cancel all the parent futures.
- TestFileGroupPopulator testFileGroupPopulator = new TestFileGroupPopulator(context);
+ Optional<String> instanceId = Optional.of(MddTestDependencies.randomInstanceId());
MobileDataDownload mobileDataDownload =
- MobileDataDownloadBuilder.newBuilder()
- .setContext(context)
- .setControlExecutor(CONTROL_EXECUTOR)
- .setFileDownloaderSupplier(neverFinishDownloader)
- .addFileGroupPopulator(testFileGroupPopulator)
- .setTaskScheduler(Optional.of(mockTaskScheduler))
- .setDeltaDecoderOptional(Optional.absent())
- .setFileStorage(fileStorage)
- .setNetworkUsageMonitor(mockNetworkUsageMonitor)
- .setDownloadMonitorOptional(Optional.of(mockDownloadProgressMonitor))
- .setFlagsOptional(Optional.of(flags))
+ builderForTest()
+ .setInstanceIdOptional(instanceId)
+ .setFileDownloaderSupplier(
+ () ->
+ new TestFileDownloader(TEST_DATA_RELATIVE_PATH, fileStorage, DOWNLOAD_EXECUTOR))
.build();
- testFileGroupPopulator.refreshFileGroups(mobileDataDownload).get();
+ // Create two groups which share the same file, but have different download transforms
+ DataFileGroup groupWithoutTransform =
+ DataFileGroup.newBuilder()
+ .setGroupName("groupWithoutTransform")
+ .addFile(
+ DataFile.newBuilder()
+ .setFileId("file_no_transform")
+ .setUrlToDownload(TEST_DATA_URL)
+ .setChecksum(TEST_DATA_CHECKSUM)
+ .setByteSize(TEST_DATA_BYTE_SIZE))
+ .build();
- // Now start to download the file group.
- ListenableFuture<ClientFileGroup> downloadFileGroupFuture =
- mobileDataDownload.downloadFileGroup(
- DownloadFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME).build());
+ DataFileGroup groupWithTransform =
+ DataFileGroup.newBuilder()
+ .setGroupName("groupWithTransform")
+ .addFile(
+ DataFile.newBuilder()
+ .setFileId("file_no_transform")
+ .setUrlToDownload(TEST_DATA_COMPRESS_URL)
+ .setChecksum(TEST_DATA_CHECKSUM)
+ .setByteSize(TEST_DATA_BYTE_SIZE)
+ .setDownloadedFileChecksum(TEST_DATA_COMPRESS_CHECKSUM)
+ .setDownloadedFileByteSize(TEST_DATA_COMPRESS_BYTE_SIZE)
+ .setDownloadTransforms(
+ Transforms.newBuilder()
+ .addTransform(
+ Transform.newBuilder()
+ .setCompress(
+ TransformProto.CompressTransform.getDefaultInstance())
+ .build())
+ .build())
+ .build())
+ .build();
- // Note: we could have a race condition here between when we call the
- // downloadFileGroupFuture.cancel and when the FileDownloader.startDownloading is executed.
- // The following call will ensure that we will only call cancel on the downloadFileGroupFuture
- // when the actual download has happened (the downloadTaskFuture).
- // This will block until the downloadTaskFuture starts.
- blockingFileDownloader.waitForDownloadStarted();
+ // Add both groups, then attempt to download both concurrently
+ mobileDataDownload
+ .addFileGroup(
+ AddFileGroupRequest.newBuilder().setDataFileGroup(groupWithoutTransform).build())
+ .get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS);
+ mobileDataDownload
+ .addFileGroup(AddFileGroupRequest.newBuilder().setDataFileGroup(groupWithTransform).build())
+ .get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS);
- // Cancel the downloadFileGroupFuture, it should cascade cancellation to downloadTaskFuture.
- downloadFileGroupFuture.cancel(true /*may interrupt*/);
+ ListenableFuture<ClientFileGroup> downloadWithoutTransform =
+ mobileDataDownload.downloadFileGroup(
+ DownloadFileGroupRequest.newBuilder().setGroupName("groupWithoutTransform").build());
+ ListenableFuture<ClientFileGroup> downloadWithTransform =
+ mobileDataDownload.downloadFileGroup(
+ DownloadFileGroupRequest.newBuilder().setGroupName("groupWithTransform").build());
- // Allow the download to continue and trigger our delegate FileDownloader. If the future isn't
- // cancelled, the onSuccess callback should fail the test.
- blockingFileDownloader.finishDownloading();
- blockingFileDownloader.waitForDownloadCompleted();
+ List<ClientFileGroup> downloadedGroups =
+ Futures.allAsList(ImmutableList.of(downloadWithoutTransform, downloadWithTransform))
+ .get(MAX_MULTI_MDD_API_WAIT_TIME_SECS, SECONDS);
- assertThat(downloadFileGroupFuture.isCancelled()).isTrue();
+ // Both groups are downloaded and both files point to the same on-device uri.
+ assertThat(downloadedGroups).doesNotContain(null);
+ assertThat(downloadedGroups.get(0).getFile(0).getFileUri())
+ .isEqualTo(downloadedGroups.get(1).getFile(0).getFileUri());
+ }
- mobileDataDownload.clear().get();
+ /**
+ * Returns MDD Builder with common dependencies set -- additional dependencies are added in each
+ * test as needed.
+ */
+ private MobileDataDownloadBuilder builderForTest() {
+
+ return MobileDataDownloadBuilder.newBuilder()
+ .setContext(context)
+ .setControlExecutor(controlExecutor)
+ .setFileStorage(fileStorage)
+ .setTaskScheduler(Optional.of(mockTaskScheduler))
+ .setDeltaDecoderOptional(Optional.absent())
+ .setNetworkUsageMonitor(mockNetworkUsageMonitor)
+ .setDownloadMonitorOptional(Optional.of(mockDownloadProgressMonitor))
+ .setFlagsOptional(Optional.of(flags));
}
}