563 lines
25 KiB
Java
563 lines
25 KiB
Java
/*
|
|
* 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.TestFileGroupPopulator.FILE_CHECKSUM;
|
|
import static com.google.android.libraries.mobiledatadownload.TestFileGroupPopulator.FILE_GROUP_NAME;
|
|
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 android.accounts.Account;
|
|
import android.content.Context;
|
|
import android.net.Uri;
|
|
import android.util.Log;
|
|
import androidx.test.core.app.ApplicationProvider;
|
|
import com.google.android.libraries.mobiledatadownload.account.AccountUtil;
|
|
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.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.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 org.junit.Before;
|
|
import org.junit.Rule;
|
|
import org.junit.Test;
|
|
import org.junit.runner.RunWith;
|
|
import org.mockito.Mock;
|
|
import org.mockito.junit.MockitoJUnit;
|
|
import org.mockito.junit.MockitoRule;
|
|
|
|
/**
|
|
* 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 = 60;
|
|
private static final int MAX_MULTI_MDD_API_WAIT_TIME_SECS = 120;
|
|
private static final long MAX_MDD_API_WAIT_TIME_SECS = 5L;
|
|
|
|
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";
|
|
|
|
private static final String FILE_ID_1 = "test-file-1";
|
|
private static final String FILE_ID_2 = "test-file-2";
|
|
private static final String FILE_CHECKSUM_1 = "a1cba9d87b1440f41ce9e7da38c43e1f6bd7d5df";
|
|
private static final String FILE_CHECKSUM_2 = "cb2459d9f1b508993aba36a5ffd942a7e0d49ed6";
|
|
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;
|
|
@Mock private NetworkUsageMonitor mockNetworkUsageMonitor;
|
|
@Mock private DownloadProgressMonitor mockDownloadProgressMonitor;
|
|
|
|
private SynchronousFileStorage fileStorage;
|
|
private ListeningExecutorService controlExecutor;
|
|
|
|
private final TestFlags flags = new TestFlags();
|
|
|
|
@Rule(order = 1)
|
|
public final MockitoRule mocks = MockitoJUnit.rule();
|
|
|
|
@TestParameter ExecutorType controlExecutorType;
|
|
|
|
@Before
|
|
public void setUp() throws Exception {
|
|
|
|
fileStorage =
|
|
new SynchronousFileStorage(
|
|
/* backends= */ ImmutableList.of(
|
|
AndroidFileBackend.builder(context).build(), new JavaFileBackend()),
|
|
/* transforms= */ ImmutableList.of(new CompressTransform()),
|
|
/* monitors= */ ImmutableList.of(mockNetworkUsageMonitor, mockDownloadProgressMonitor));
|
|
|
|
controlExecutor = controlExecutorType.executor();
|
|
}
|
|
|
|
@Test
|
|
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
|
|
}
|
|
}
|
|
|
|
@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 =
|
|
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.
|
|
DataFileGroup groupWithInsecureUrl =
|
|
TestFileGroupPopulator.createDataFileGroup(
|
|
FILE_GROUP_NAME_INSECURE_URL,
|
|
context.getPackageName(),
|
|
new String[] {FILE_ID},
|
|
new int[] {FILE_SIZE},
|
|
new String[] {FILE_CHECKSUM},
|
|
// Make the url insecure. This would lead to download failure.
|
|
new String[] {FILE_URL.replace("https", "http")},
|
|
DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK);
|
|
|
|
// The data file group has a file with non-existent url, and a file with insecure url.
|
|
DataFileGroup groupWithMultipleFiles =
|
|
TestFileGroupPopulator.createDataFileGroup(
|
|
FILE_GROUP_NAME_MULTIPLE_FILES,
|
|
context.getPackageName(),
|
|
new String[] {FILE_ID_1, FILE_ID_2},
|
|
new int[] {FILE_SIZE, FILE_SIZE},
|
|
new String[] {FILE_CHECKSUM_1, FILE_CHECKSUM_2},
|
|
// The first file url doesn't exist and the second file url is insecure.
|
|
new String[] {FILE_NOT_EXIST_URL, FILE_URL.replace("https", "http")},
|
|
DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK);
|
|
|
|
assertThat(
|
|
mobileDataDownload
|
|
.addFileGroup(
|
|
AddFileGroupRequest.newBuilder().setDataFileGroup(groupWithInsecureUrl).build())
|
|
.get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS))
|
|
.isTrue();
|
|
|
|
assertThat(
|
|
mobileDataDownload
|
|
.addFileGroup(
|
|
AddFileGroupRequest.newBuilder()
|
|
.setDataFileGroup(groupWithMultipleFiles)
|
|
.build())
|
|
.get(MAX_MDD_API_WAIT_TIME_SECS, SECONDS))
|
|
.isTrue();
|
|
|
|
ExecutionException exception =
|
|
assertThrows(
|
|
ExecutionException.class,
|
|
() ->
|
|
mobileDataDownload
|
|
.downloadFileGroup(
|
|
DownloadFileGroupRequest.newBuilder()
|
|
.setGroupName(FILE_GROUP_NAME_INSECURE_URL)
|
|
.build())
|
|
.get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS));
|
|
assertThat(exception).hasCauseThat().isInstanceOf(AggregateException.class);
|
|
AggregateException cause = (AggregateException) exception.getCause();
|
|
assertThat(cause).isNotNull();
|
|
ImmutableList<Throwable> failures = cause.getFailures();
|
|
assertThat(failures).hasSize(1);
|
|
assertThat(failures.get(0)).isInstanceOf(DownloadException.class);
|
|
assertThat(failures.get(0)).hasMessageThat().contains("INSECURE_URL_ERROR");
|
|
|
|
ExecutionException exception2 =
|
|
assertThrows(
|
|
ExecutionException.class,
|
|
() ->
|
|
mobileDataDownload
|
|
.downloadFileGroup(
|
|
DownloadFileGroupRequest.newBuilder()
|
|
.setGroupName(FILE_GROUP_NAME_MULTIPLE_FILES)
|
|
.build())
|
|
.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);
|
|
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");
|
|
|
|
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);
|
|
}
|
|
|
|
@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 =
|
|
builderForTest()
|
|
.setInstanceIdOptional(instanceId)
|
|
.setFileDownloaderSupplier(() -> blockingFileDownloader)
|
|
.build();
|
|
|
|
mobileDataDownload.clear().get(MAX_MDD_API_WAIT_TIME_SECS, 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);
|
|
|
|
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(MAX_MDD_API_WAIT_TIME_SECS, SECONDS);
|
|
|
|
assertThat(clientFileGroup).isNotNull();
|
|
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
|
|
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);
|
|
|
|
// Start all downloads concurrently
|
|
ArrayList<ListenableFuture<ClientFileGroup>> downloadFutures = new ArrayList<>();
|
|
for (int i = 0; i < 50; i++) {
|
|
String groupName = String.format("group%d", i);
|
|
|
|
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 concurrentDownloads_withSameFile_withDifferentDownloadTransforms_completes(
|
|
@TestParameter boolean enableDedupByFileKey) throws Exception {
|
|
flags.enableFileDownloadDedupByFileKey = Optional.of(enableDedupByFileKey);
|
|
|
|
Optional<String> instanceId = Optional.of(MddTestDependencies.randomInstanceId());
|
|
MobileDataDownload mobileDataDownload =
|
|
builderForTest()
|
|
.setInstanceIdOptional(instanceId)
|
|
.setFileDownloaderSupplier(
|
|
() ->
|
|
new TestFileDownloader(TEST_DATA_RELATIVE_PATH, fileStorage, DOWNLOAD_EXECUTOR))
|
|
.build();
|
|
|
|
// 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();
|
|
|
|
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();
|
|
|
|
// 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);
|
|
|
|
ListenableFuture<ClientFileGroup> downloadWithoutTransform =
|
|
mobileDataDownload.downloadFileGroup(
|
|
DownloadFileGroupRequest.newBuilder().setGroupName("groupWithoutTransform").build());
|
|
ListenableFuture<ClientFileGroup> downloadWithTransform =
|
|
mobileDataDownload.downloadFileGroup(
|
|
DownloadFileGroupRequest.newBuilder().setGroupName("groupWithTransform").build());
|
|
|
|
List<ClientFileGroup> downloadedGroups =
|
|
Futures.allAsList(ImmutableList.of(downloadWithoutTransform, downloadWithTransform))
|
|
.get(MAX_MULTI_MDD_API_WAIT_TIME_SECS, SECONDS);
|
|
|
|
// 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());
|
|
}
|
|
|
|
/**
|
|
* 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));
|
|
}
|
|
}
|