blob: b98cd361e937a19f4ef5f540fb4a7b88a8d5d926 [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.common.labs.truth.FutureSubject.assertThat;
import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.accounts.Account;
import android.content.Context;
import android.net.Uri;
import android.util.Pair;
import androidx.test.core.app.ApplicationProvider;
import com.google.android.libraries.mobiledatadownload.DownloadException.DownloadResultCode;
import com.google.android.libraries.mobiledatadownload.TaskScheduler.ConstraintOverrides;
import com.google.android.libraries.mobiledatadownload.TaskScheduler.NetworkState;
import com.google.android.libraries.mobiledatadownload.account.AccountUtil;
import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage;
import com.google.android.libraries.mobiledatadownload.file.backends.AndroidFileBackend;
import com.google.android.libraries.mobiledatadownload.file.openers.WriteStreamOpener;
import com.google.android.libraries.mobiledatadownload.internal.MobileDataDownloadManager;
import com.google.android.libraries.mobiledatadownload.internal.logging.EventLogger;
import com.google.android.libraries.mobiledatadownload.internal.util.ProtoConversionUtil;
import com.google.android.libraries.mobiledatadownload.lite.Downloader;
import com.google.android.libraries.mobiledatadownload.monitor.DownloadProgressMonitor;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.labs.concurrent.LabsFutures;
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.MoreExecutors;
import com.google.mobiledatadownload.ClientConfigProto.ClientFile;
import com.google.mobiledatadownload.ClientConfigProto.ClientFileGroup;
import com.google.mobiledatadownload.ClientConfigProto.ClientFileGroup.Status;
import com.google.mobiledatadownload.DownloadConfigProto.DataFile;
import com.google.mobiledatadownload.DownloadConfigProto.DataFileGroup;
import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions;
import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions.DeviceNetworkPolicy;
import com.google.mobiledatadownload.internal.MetadataProto;
import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupInternal;
import com.google.mobiledatadownload.internal.MetadataProto.GroupKey;
import com.google.protobuf.Any;
import com.google.protobuf.ByteString;
import com.google.protobuf.StringValue;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
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;
/** Tests for {@link com.google.android.libraries.mobiledatadownload.MobileDataDownload}. */
@RunWith(RobolectricTestRunner.class)
public class MobileDataDownloadTest {
// Note: Control Executor must not be a single thread executor.
private static final Executor EXECUTOR = Executors.newCachedThreadPool();
private static final long LATCH_WAIT_TIME_MS = 1000L;
private static final String FILE_GROUP_NAME_1 = "test-group-1";
private static final String FILE_GROUP_NAME_2 = "test-group-2";
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 = "c1ef7864c76a99ae738ddad33882ed65972c99cc";
private static final String FILE_URL_1 = "https://www.gstatic.com/suggest-dev/odws1_test_4.jar";
private static final int FILE_SIZE_1 = 85769;
private static final String FILE_CHECKSUM_2 = "a1cba9d87b1440f41ce9e7da38c43e1f6bd7d5df";
private static final String FILE_URL_2 = "https://www.gstatic.com/suggest-dev/odws1_empty.jar";
private static final int FILE_SIZE_2 = 554;
private final Uri onDeviceUri1 =
Uri.parse(
"android://com.google.android.libraries.mobiledatadownload/files/datadownload/shared/public/file_1");
private final Uri onDeviceDirUri =
Uri.parse(
"android://com.google.android.libraries.mobiledatadownload/files/datadownload/shared/public/dir");
private final Uri onDeviceDirFileUri1 =
Uri.parse(
"android://com.google.android.libraries.mobiledatadownload/files/datadownload/shared/public/dir/file_1");
private final String onDeviceDirFile1Content = "Test file 1.";
private final Uri onDeviceDirFileUri2 =
Uri.parse(
"android://com.google.android.libraries.mobiledatadownload/files/datadownload/shared/public/dir/file_2");
private final String onDeviceDirFile2Content = "Test file 2.";
private final Uri onDeviceDirFileUri3 =
Uri.parse(
"android://com.google.android.libraries.mobiledatadownload/files/datadownload/shared/public/dir/sub/file");
private final String onDeviceDirFile3Content = "Test file 3 in sub-dir.";
private final Flags flags = new Flags() {};
private Context context;
private SynchronousFileStorage fileStorage;
@Mock EventLogger mockEventLogger;
@Mock MobileDataDownloadManager mockMobileDataDownloadManager;
@Mock TaskScheduler mockTaskScheduler;
@Mock FileGroupPopulator mockFileGroupPopulator;
@Mock DownloadProgressMonitor mockDownloadMonitor;
@Mock Downloader singleFileDownloader;
@Captor ArgumentCaptor<GroupKey> groupKeyCaptor;
@Captor ArgumentCaptor<List<GroupKey>> groupKeysCaptor;
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
@Before
public void setUp() throws IOException {
context = ApplicationProvider.getApplicationContext();
fileStorage =
new SynchronousFileStorage(
ImmutableList.of(AndroidFileBackend.builder(context).build()) /*backends*/);
createFile(onDeviceUri1, "test");
fileStorage.createDirectory(onDeviceDirUri);
createFile(onDeviceDirFileUri1, onDeviceDirFile1Content);
createFile(onDeviceDirFileUri2, onDeviceDirFile2Content);
createFile(onDeviceDirFileUri3, onDeviceDirFile3Content);
}
private void createFile(Uri uri, String content) throws IOException {
try (OutputStream out = fileStorage.open(uri, WriteStreamOpener.create())) {
out.write(content.getBytes(UTF_8));
}
}
@Test
public void buildGetFileGroupsByFilterRequest() throws Exception {
Account account = AccountUtil.create("account-name", "account-type");
GetFileGroupsByFilterRequest request1 =
GetFileGroupsByFilterRequest.newBuilder()
.setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1))
.setAccountOptional(Optional.of(account))
.build();
assertThat(request1.groupNameOptional()).hasValue(FILE_GROUP_NAME_1);
assertThat(request1.accountOptional()).hasValue(account);
GetFileGroupsByFilterRequest request2 =
GetFileGroupsByFilterRequest.newBuilder()
.setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1))
.build();
assertThat(request2.groupNameOptional()).hasValue(FILE_GROUP_NAME_1);
assertThat(request2.accountOptional()).isAbsent();
GetFileGroupsByFilterRequest.Builder builder = GetFileGroupsByFilterRequest.newBuilder();
assertThrows(IllegalArgumentException.class, builder::build);
}
@Test
public void buildGetFileGroupsByFilterRequest_groupWithNoAccountOnly() {
Account account = AccountUtil.create("account-name", "account-type");
GetFileGroupsByFilterRequest.Builder builder =
GetFileGroupsByFilterRequest.newBuilder()
.setGroupWithNoAccountOnly(true)
.setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1))
.setAccountOptional(Optional.of(account));
// Make sure that when request account independent groups, accountOptional should be absent.
assertThrows(IllegalArgumentException.class, builder::build);
}
@Test
public void addFileGroup() throws Exception {
when(mockMobileDataDownloadManager.addGroupForDownloadInternal(
any(GroupKey.class), any(DataFileGroupInternal.class), any()))
.thenReturn(Futures.immediateFuture(true));
DataFileGroup dataFileGroup =
createDataFileGroup(
FILE_GROUP_NAME_1,
context.getPackageName(),
1 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
assertThat(
mobileDataDownload
.addFileGroup(
AddFileGroupRequest.newBuilder().setDataFileGroup(dataFileGroup).build())
.get())
.isTrue();
}
@Test
public void addFileGroup_onFailure() throws Exception {
when(mockMobileDataDownloadManager.addGroupForDownloadInternal(
any(GroupKey.class), any(DataFileGroupInternal.class), any()))
.thenReturn(Futures.immediateFuture(false));
DataFileGroup dataFileGroup =
createDataFileGroup(
FILE_GROUP_NAME_1,
context.getPackageName(),
1 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
assertThat(
mobileDataDownload
.addFileGroup(
AddFileGroupRequest.newBuilder().setDataFileGroup(dataFileGroup).build())
.get())
.isFalse();
}
@Test
public void addFileGroup_invalidOwnerPackageName() throws Exception {
when(mockMobileDataDownloadManager.addGroupForDownloadInternal(
any(GroupKey.class), any(DataFileGroupInternal.class), any()))
.thenReturn(Futures.immediateFuture(true));
// Owner Package should be same as the app package.
DataFileGroup dataFileGroup =
createDataFileGroup(
FILE_GROUP_NAME_1,
"PACKAGE_NAME",
1 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
null /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
assertThat(
mobileDataDownload
.addFileGroup(
AddFileGroupRequest.newBuilder().setDataFileGroup(dataFileGroup).build())
.get())
.isFalse();
}
@Test
public void addFileGroupWithFileGroupKey() throws Exception {
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.addGroupForDownloadInternal(
groupKeyCaptor.capture(), any(DataFileGroupInternal.class), any()))
.thenReturn(Futures.immediateFuture(true));
DataFileGroup dataFileGroup =
createDataFileGroup(
FILE_GROUP_NAME_1,
context.getPackageName(),
1 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
Account account = AccountUtil.create("account-name", "account-type");
AddFileGroupRequest addFileGroupRequest =
AddFileGroupRequest.newBuilder()
.setDataFileGroup(dataFileGroup)
.setAccountOptional(Optional.of(account))
.build();
assertThat(mobileDataDownload.addFileGroup(addFileGroupRequest).get()).isTrue();
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setAccount(AccountUtil.serialize(account))
.build();
assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey);
verify(mockMobileDataDownloadManager)
.addGroupForDownloadInternal(
eq(groupKey), eq(ProtoConversionUtil.convert(dataFileGroup)), any());
}
@Test
public void addFileGroupWithFileGroupKey_onFailure() throws Exception {
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.addGroupForDownloadInternal(
groupKeyCaptor.capture(), any(DataFileGroupInternal.class), any()))
.thenReturn(Futures.immediateFuture(false));
DataFileGroup dataFileGroup =
createDataFileGroup(
FILE_GROUP_NAME_1,
context.getPackageName(),
1 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
Account account = AccountUtil.create("account-name", "account-type");
AddFileGroupRequest addFileGroupRequest =
AddFileGroupRequest.newBuilder()
.setDataFileGroup(dataFileGroup)
.setAccountOptional(Optional.of(account))
.build();
assertThat(mobileDataDownload.addFileGroup(addFileGroupRequest).get()).isFalse();
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setAccount(AccountUtil.serialize(account))
.build();
assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey);
verify(mockMobileDataDownloadManager)
.addGroupForDownloadInternal(
eq(groupKey), eq(ProtoConversionUtil.convert(dataFileGroup)), any());
}
@Test
public void addFileGroupWithFileGroupKey_nullAccount() throws Exception {
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.addGroupForDownloadInternal(
groupKeyCaptor.capture(), any(DataFileGroupInternal.class), any()))
.thenReturn(Futures.immediateFuture(true));
DataFileGroup dataFileGroup =
createDataFileGroup(
FILE_GROUP_NAME_1,
context.getPackageName(),
1 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
AddFileGroupRequest addFileGroupRequest =
AddFileGroupRequest.newBuilder().setDataFileGroup(dataFileGroup).build();
assertThat(mobileDataDownload.addFileGroup(addFileGroupRequest).get()).isTrue();
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.build();
assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey);
verify(mockMobileDataDownloadManager)
.addGroupForDownloadInternal(
eq(groupKey), eq(ProtoConversionUtil.convert(dataFileGroup)), any());
}
@Test
public void addFileGroupWithFileGroupKey_withVariant() throws Exception {
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.addGroupForDownloadInternal(
groupKeyCaptor.capture(), any(), any()))
.thenReturn(Futures.immediateFuture(true));
DataFileGroup dataFileGroupWithVariant =
createDataFileGroup(
FILE_GROUP_NAME_1,
context.getPackageName(),
1 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI)
.toBuilder()
.setVariantId("en")
.build();
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
AddFileGroupRequest addFileGroupRequest =
AddFileGroupRequest.newBuilder()
.setDataFileGroup(dataFileGroupWithVariant)
.setVariantIdOptional(Optional.of("en"))
.build();
assertThat(mobileDataDownload.addFileGroup(addFileGroupRequest).get()).isTrue();
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setVariantId("en")
.build();
assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey);
verify(mockMobileDataDownloadManager)
.addGroupForDownloadInternal(
eq(groupKey), eq(ProtoConversionUtil.convert(dataFileGroupWithVariant)), any());
}
@Test
public void removeFileGroup_onSuccess_returnsTrue() throws Exception {
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.removeFileGroup(groupKeyCaptor.capture(), eq(false)))
.thenReturn(Futures.immediateFuture(null /* Void */));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
RemoveFileGroupRequest removeFileGroupRequest =
RemoveFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build();
assertThat(mobileDataDownload.removeFileGroup(removeFileGroupRequest).get()).isTrue();
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.build();
assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey);
}
@Test
public void removeFileGroup_onFailure_returnsFalse() throws Exception {
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
doThrow(new IOException())
.when(mockMobileDataDownloadManager)
.removeFileGroup(groupKeyCaptor.capture(), /* pendingOnly= */ eq(false));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
RemoveFileGroupRequest removeFileGroupRequest =
RemoveFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build();
ExecutionException exception =
assertThrows(
ExecutionException.class,
() -> mobileDataDownload.removeFileGroup(removeFileGroupRequest).get());
assertThat(exception).hasCauseThat().isInstanceOf(IOException.class);
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.build();
assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey);
}
@Test
public void removeFileGroup_withAccount_returnsTrue() throws Exception {
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.removeFileGroup(
groupKeyCaptor.capture(), /* pendingOnly= */ eq(false)))
.thenReturn(Futures.immediateFuture(null /* Void */));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
Account account = AccountUtil.create("account-name", "account-type");
RemoveFileGroupRequest removeFileGroupRequest =
RemoveFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setAccountOptional(Optional.of(account))
.build();
assertThat(mobileDataDownload.removeFileGroup(removeFileGroupRequest).get()).isTrue();
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setAccount(AccountUtil.serialize(account))
.build();
assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey);
}
@Test
public void removeFileGroup_withVariantId_returnsTrue() throws Exception {
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.removeFileGroup(
groupKeyCaptor.capture(), /* pendingOnly= */ eq(false)))
.thenReturn(Futures.immediateFuture(null /* Void */));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
RemoveFileGroupRequest removeFileGroupRequest =
RemoveFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setVariantIdOptional(Optional.of("en"))
.build();
assertThat(mobileDataDownload.removeFileGroup(removeFileGroupRequest).get()).isTrue();
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setVariantId("en")
.build();
assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey);
}
@Test
public void getFileGroup() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI)
.toBuilder()
.setBuildId(10)
.setVariantId("test-variant")
.build();
when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ClientFileGroup clientFileGroup =
mobileDataDownload
.getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build())
.get();
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
assertThat(clientFileGroup.hasAccount()).isFalse();
ClientFile clientFile = clientFileGroup.getFileList().get(0);
assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1);
assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString());
}
@Test
public void getFileGroup_withDirectory() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceDirUri));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ClientFileGroup clientFileGroup =
mobileDataDownload
.getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build())
.get();
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getFileCount()).isEqualTo(3);
assertThat(clientFileGroup.hasAccount()).isFalse();
List<ClientFile> clientFileList = clientFileGroup.getFileList();
assertThat(clientFileList)
.contains(
ClientFile.newBuilder()
.setFileId("/file_1")
.setFileUri(onDeviceDirFileUri1.toString())
.setFullSizeInBytes(onDeviceDirFile1Content.getBytes(UTF_8).length)
.build());
assertThat(clientFileList)
.contains(
ClientFile.newBuilder()
.setFileId("/file_2")
.setFileUri(onDeviceDirFileUri2.toString())
.setFullSizeInBytes(onDeviceDirFile2Content.getBytes(UTF_8).length)
.build());
assertThat(clientFileList)
.contains(
ClientFile.newBuilder()
.setFileId("/sub/file")
.setFileUri(onDeviceDirFileUri3.toString())
.setFullSizeInBytes(onDeviceDirFile3Content.getBytes(UTF_8).length)
.build());
}
@Test
public void getFileGroup_withDirectory_withTraverseDisabled() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceDirUri));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ClientFileGroup clientFileGroup =
mobileDataDownload
.getFileGroup(
GetFileGroupRequest.newBuilder()
.setPreserveZipDirectories(true)
.setGroupName(FILE_GROUP_NAME_1)
.build())
.get();
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
assertThat(clientFileGroup.hasAccount()).isFalse();
List<ClientFile> clientFileList = clientFileGroup.getFileList();
assertThat(clientFileList)
.contains(
ClientFile.newBuilder()
.setFileId("test-file-1")
.setFileUri(onDeviceDirUri.toString())
.setFullSizeInBytes(FILE_SIZE_1)
.build());
assertThat(fileStorage.isDirectory(Uri.parse(clientFileList.get(0).getFileUri()))).isTrue();
}
@Test
public void removeFileGroupsByFilter_withAccountSpecified_removesMatchingAccountGroups()
throws Exception {
List<Pair<GroupKey, DataFileGroupInternal>> keyToGroupList = new ArrayList<>();
Account account1 = AccountUtil.create("account-name", "account-type");
Account account2 = AccountUtil.create("account-name2", "account-type");
DataFileGroupInternal downloadedFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
/* versionNumber = */ 5,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI)
.toBuilder()
.build();
DataFileGroupInternal pendingFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
/* versionNumber = */ 6,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI)
.toBuilder()
.build();
GroupKey account1GroupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setAccount(AccountUtil.serialize(account1))
.build();
GroupKey downloadedAccount1GroupKey = account1GroupKey.toBuilder().setDownloaded(true).build();
GroupKey pendingAccount1GroupKey = account1GroupKey.toBuilder().setDownloaded(false).build();
GroupKey account2GroupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setAccount(AccountUtil.serialize(account2))
.build();
GroupKey downloadedAccount2GroupKey = account2GroupKey.toBuilder().setDownloaded(true).build();
GroupKey pendingAccount2GroupKey = account2GroupKey.toBuilder().setDownloaded(false).build();
GroupKey noAccountGroupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.build();
GroupKey downloadedGroupKey = noAccountGroupKey.toBuilder().setDownloaded(true).build();
GroupKey pendingGroupKey = noAccountGroupKey.toBuilder().setDownloaded(false).build();
keyToGroupList.add(Pair.create(downloadedGroupKey, downloadedFileGroup));
keyToGroupList.add(Pair.create(downloadedAccount1GroupKey, downloadedFileGroup));
keyToGroupList.add(Pair.create(downloadedAccount2GroupKey, downloadedFileGroup));
keyToGroupList.add(Pair.create(pendingGroupKey, pendingFileGroup));
keyToGroupList.add(Pair.create(pendingAccount1GroupKey, pendingFileGroup));
keyToGroupList.add(Pair.create(pendingAccount2GroupKey, pendingFileGroup));
when(mockMobileDataDownloadManager.getAllFreshGroups())
.thenReturn(Futures.immediateFuture(keyToGroupList));
when(mockMobileDataDownloadManager.removeFileGroups(groupKeysCaptor.capture()))
.thenReturn(Futures.immediateVoidFuture());
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
/* foregroundDownloadServiceClassOptional = */ Optional.absent(),
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
// Setup request that matches all fresh groups, but also include account to make sure only
// account associated file groups are removed
RemoveFileGroupsByFilterRequest removeFileGroupsByFilterRequest =
RemoveFileGroupsByFilterRequest.newBuilder()
.setAccountOptional(Optional.of(account1))
.build();
RemoveFileGroupsByFilterResponse response =
mobileDataDownload.removeFileGroupsByFilter(removeFileGroupsByFilterRequest).get();
assertThat(response.removedFileGroupsCount()).isEqualTo(1);
verify(mockMobileDataDownloadManager, times(1)).removeFileGroups(anyList());
List<GroupKey> removedGroupKeys = groupKeysCaptor.getValue();
assertThat(removedGroupKeys).containsExactly(account1GroupKey);
}
@Test
public void getFileGroup_nullFileUri() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(
Futures.immediateFailedFuture(
DownloadException.builder()
.setDownloadResultCode(DownloadResultCode.UNKNOWN_ERROR)
.setMessage("Fail to download file group")
.build()));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
assertNull(
mobileDataDownload
.getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build())
.get());
}
@Test
public void getFileGroup_null() throws Exception {
when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true)))
.thenReturn(Futures.immediateFuture(null));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
assertNull(
mobileDataDownload
.getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build())
.get());
verifyNoInteractions(mockEventLogger);
}
@Test
public void getFileGroup_withAccount() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(true)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
Account account = AccountUtil.create("account-name", "account-type");
ClientFileGroup clientFileGroup =
mobileDataDownload
.getFileGroup(
GetFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setAccountOptional(Optional.of(account))
.build())
.get();
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account));
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
ClientFile clientFile = clientFileGroup.getFileList().get(0);
assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1);
assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString());
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setAccount(AccountUtil.serialize(account))
.build();
assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey);
}
@Test
public void getFileGroup_withVariantId() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI)
.toBuilder()
.setVariantId("en")
.build();
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(true)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ClientFileGroup clientFileGroup =
mobileDataDownload
.getFileGroup(
GetFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setVariantIdOptional(Optional.of("en"))
.build())
.get();
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getAccount()).isEmpty();
assertThat(clientFileGroup.getVariantId()).isEqualTo("en");
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setVariantId("en")
.build();
assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey);
}
@Test
public void getFileGroup_includesIdentifyingProperties() throws Exception {
Any customProperty =
Any.newBuilder()
.setTypeUrl("type.googleapis.com/google.protobuf.stringvalue")
.setValue(StringValue.of("TEST_PROPERTY").toByteString())
.build();
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI)
.toBuilder()
.setBuildId(1L)
.setVariantId("testvariant")
.setCustomProperty(customProperty)
.build();
when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ClientFileGroup clientFileGroup =
mobileDataDownload
.getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build())
.get();
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getBuildId()).isEqualTo(1L);
assertThat(clientFileGroup.getVariantId()).isEqualTo("testvariant");
assertThat(clientFileGroup.getCustomProperty()).isEqualTo(customProperty);
}
@Test
public void getFileGroup_includesLocale() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI)
.toBuilder()
.addLocale("en-US")
.addLocale("en-CA")
.build();
when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ClientFileGroup clientFileGroup =
mobileDataDownload
.getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build())
.get();
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getLocaleList()).containsExactly("en-US", "en-CA");
}
@Test
public void getFileGroup_includesGroupLevelMetadataWhenProvided() throws Exception {
Any customMetadata =
Any.newBuilder()
.setTypeUrl("type.googleapis.com/google.protobuf.stringvalue")
.setValue(StringValue.of("TEST_METADATA").toByteString())
.build();
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI)
.toBuilder()
.setCustomMetadata(customMetadata)
.build();
when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ClientFileGroup clientFileGroup =
mobileDataDownload
.getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build())
.get();
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getCustomMetadata()).isEqualTo(customMetadata);
}
@Test
public void getFileGroup_includesFileLevelMetadataWhenProvided() throws Exception {
Any customMetadata =
Any.newBuilder()
.setTypeUrl("type.googleapis.com/google.protobuf.stringvalue")
.setValue(StringValue.of("TEST_METADATA").toByteString())
.build();
DataFileGroupInternal dataFileGroup =
DataFileGroupInternal.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.addFile(
MetadataProto.DataFile.newBuilder()
.setFileId(FILE_ID_1)
.setUrlToDownload(FILE_URL_1)
.setCustomMetadata(customMetadata)
.build())
.addFile(
MetadataProto.DataFile.newBuilder()
.setFileId(FILE_ID_2)
.setUrlToDownload(FILE_URL_2)
.build())
.build();
when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(1), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ClientFileGroup clientFileGroup =
mobileDataDownload
.getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build())
.get();
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.hasCustomMetadata()).isFalse();
ClientFile clientFile1 =
clientFileGroup.getFile(0).getFileId().equals(FILE_ID_1)
? clientFileGroup.getFile(0)
: clientFileGroup.getFile(1);
ClientFile clientFile2 =
clientFileGroup.getFile(0).getFileId().equals(FILE_ID_1)
? clientFileGroup.getFile(1)
: clientFileGroup.getFile(0);
assertThat(clientFile1.hasCustomMetadata()).isTrue();
assertThat(clientFile1.getCustomMetadata()).isEqualTo(customMetadata);
assertThat(clientFile2.hasCustomMetadata()).isFalse();
}
@Test
public void getFileGroupsByFilter_singleGroup() throws Exception {
List<Pair<GroupKey, DataFileGroupInternal>> keyDataFileGroupList = new ArrayList<>();
DataFileGroupInternal downloadedFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.build();
when(mockMobileDataDownloadManager.getFileGroup(eq(groupKey), eq(true)))
.thenReturn(Futures.immediateFuture(downloadedFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(
downloadedFileGroup.getFile(0), downloadedFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
keyDataFileGroupList.add(
Pair.create(groupKey.toBuilder().setDownloaded(true).build(), downloadedFileGroup));
DataFileGroupInternal pendingFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
7 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_2},
new String[] {FILE_CHECKSUM_2},
new String[] {FILE_URL_2},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
pendingFileGroup =
pendingFileGroup.toBuilder()
.setFile(0, pendingFileGroup.getFile(0).toBuilder().setDownloadedFileByteSize(222222))
.build();
when(mockMobileDataDownloadManager.getFileGroup(groupKey, false))
.thenReturn(Futures.immediateFuture(pendingFileGroup));
keyDataFileGroupList.add(
Pair.create(groupKey.toBuilder().setDownloaded(false).build(), pendingFileGroup));
DataFileGroupInternal pendingFileGroup2 =
createDataFileGroupInternal(
FILE_GROUP_NAME_2,
context.getPackageName(),
4 /* versionNumber */,
new String[] {FILE_ID_1, FILE_ID_2},
new int[] {FILE_SIZE_1, FILE_SIZE_2},
new String[] {FILE_CHECKSUM_1, FILE_CHECKSUM_2},
new String[] {FILE_URL_1, FILE_URL_2},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
GroupKey groupKey2 =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_2)
.setOwnerPackage(context.getPackageName())
.build();
when(mockMobileDataDownloadManager.getFileGroup(groupKey2, false))
.thenReturn(Futures.immediateFuture(pendingFileGroup2));
keyDataFileGroupList.add(
Pair.create(groupKey2.toBuilder().setDownloaded(false).build(), pendingFileGroup2));
when(mockMobileDataDownloadManager.getAllFreshGroups())
.thenReturn(Futures.immediateFuture(keyDataFileGroupList));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
// We should get back 2 groups for FILE_GROUP_NAME_1.
GetFileGroupsByFilterRequest getFileGroupsByFilterRequest =
GetFileGroupsByFilterRequest.newBuilder()
.setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1))
.build();
ImmutableList<ClientFileGroup> clientFileGroups =
mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get();
assertThat(clientFileGroups).hasSize(2);
ClientFileGroup downloadedClientFileGroup = clientFileGroups.get(0);
assertThat(downloadedClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(downloadedClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(downloadedClientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(downloadedClientFileGroup.getStatus()).isEqualTo(Status.DOWNLOADED);
assertThat(downloadedClientFileGroup.getFileCount()).isEqualTo(1);
assertThat(downloadedClientFileGroup.hasAccount()).isFalse();
ClientFile clientFile = downloadedClientFileGroup.getFileList().get(0);
assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1);
assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString());
assertThat(clientFile.getFullSizeInBytes()).isEqualTo(FILE_SIZE_1);
ClientFileGroup pendingClientFileGroup = clientFileGroups.get(1);
assertThat(pendingClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(pendingClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(pendingClientFileGroup.getVersionNumber()).isEqualTo(7);
assertThat(pendingClientFileGroup.getStatus()).isEqualTo(Status.PENDING);
assertThat(pendingClientFileGroup.getFileCount()).isEqualTo(1);
assertThat(pendingClientFileGroup.hasAccount()).isFalse();
clientFile = pendingClientFileGroup.getFileList().get(0);
assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1);
assertThat(clientFile.getDownloadSizeInBytes()).isEqualTo(222222);
assertThat(clientFile.getFileUri()).isEmpty();
// We should get back 1 group for FILE_GROUP_NAME_2.
getFileGroupsByFilterRequest =
GetFileGroupsByFilterRequest.newBuilder()
.setGroupNameOptional(Optional.of(FILE_GROUP_NAME_2))
.build();
clientFileGroups = mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get();
ClientFileGroup pendingClientFileGroup2 = clientFileGroups.get(0);
assertThat(pendingClientFileGroup2.getGroupName()).isEqualTo(FILE_GROUP_NAME_2);
assertThat(pendingClientFileGroup2.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(pendingClientFileGroup2.getVersionNumber()).isEqualTo(4);
assertThat(pendingClientFileGroup2.getStatus()).isEqualTo(Status.PENDING);
assertThat(pendingClientFileGroup2.getFileCount()).isEqualTo(2);
assertThat(pendingClientFileGroup2.hasAccount()).isFalse();
}
@Test
public void getFileGroupsByFilter_includeAllGroups() throws Exception {
List<Pair<GroupKey, DataFileGroupInternal>> keyDataFileGroupList = new ArrayList<>();
Account account = AccountUtil.create("account-name", "account-type");
DataFileGroupInternal downloadedFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setAccount(AccountUtil.serialize(account))
.build();
when(mockMobileDataDownloadManager.getDataFileUri(
downloadedFileGroup.getFile(0), downloadedFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
keyDataFileGroupList.add(
Pair.create(groupKey.toBuilder().setDownloaded(true).build(), downloadedFileGroup));
DataFileGroupInternal pendingFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
7,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_2},
new String[] {FILE_CHECKSUM_2},
new String[] {FILE_URL_2},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
keyDataFileGroupList.add(
Pair.create(groupKey.toBuilder().setDownloaded(false).build(), pendingFileGroup));
DataFileGroupInternal pendingFileGroup2 =
createDataFileGroupInternal(
FILE_GROUP_NAME_2,
context.getPackageName(),
4 /* versionNumber */,
new String[] {FILE_ID_1, FILE_ID_2},
new int[] {FILE_SIZE_1, FILE_SIZE_2},
new String[] {FILE_CHECKSUM_1, FILE_CHECKSUM_2},
new String[] {FILE_URL_1, FILE_URL_2},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
GroupKey groupKey2 =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_2)
.setOwnerPackage(context.getPackageName())
.build();
when(mockMobileDataDownloadManager.getFileGroup(groupKey2, false))
.thenReturn(Futures.immediateFuture(pendingFileGroup2));
keyDataFileGroupList.add(
Pair.create(groupKey2.toBuilder().setDownloaded(false).build(), pendingFileGroup2));
when(mockMobileDataDownloadManager.getAllFreshGroups())
.thenReturn(Futures.immediateFuture(keyDataFileGroupList));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
// We should get back all 3 groups for this key.
GetFileGroupsByFilterRequest getFileGroupsByFilterRequest =
GetFileGroupsByFilterRequest.newBuilder().setIncludeAllGroups(true).build();
List<ClientFileGroup> clientFileGroups =
mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get();
assertThat(clientFileGroups).hasSize(3);
ClientFileGroup downloadedClientFileGroup = clientFileGroups.get(0);
assertThat(downloadedClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(downloadedClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(downloadedClientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(downloadedClientFileGroup.getStatus()).isEqualTo(Status.DOWNLOADED);
assertThat(downloadedClientFileGroup.getFileCount()).isEqualTo(1);
assertThat(downloadedClientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account));
ClientFile clientFile = downloadedClientFileGroup.getFileList().get(0);
assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1);
assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString());
assertThat(clientFile.getFullSizeInBytes()).isEqualTo(FILE_SIZE_1);
ClientFileGroup pendingClientFileGroup = clientFileGroups.get(1);
assertThat(pendingClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(pendingClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(pendingClientFileGroup.getVersionNumber()).isEqualTo(7);
assertThat(pendingClientFileGroup.getStatus()).isEqualTo(Status.PENDING);
assertThat(pendingClientFileGroup.getFileCount()).isEqualTo(1);
assertThat(pendingClientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account));
clientFile = pendingClientFileGroup.getFileList().get(0);
assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1);
assertThat(clientFile.getFileUri()).isEmpty();
ClientFileGroup pendingClientFileGroup2 = clientFileGroups.get(2);
assertThat(pendingClientFileGroup2.getGroupName()).isEqualTo(FILE_GROUP_NAME_2);
assertThat(pendingClientFileGroup2.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(pendingClientFileGroup2.getVersionNumber()).isEqualTo(4);
assertThat(pendingClientFileGroup2.getStatus()).isEqualTo(Status.PENDING);
assertThat(pendingClientFileGroup2.getFileCount()).isEqualTo(2);
assertThat(pendingClientFileGroup2.hasAccount()).isFalse();
}
@Test
public void getFileGroupsByFilter_noData() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
when(mockMobileDataDownloadManager.getAllFreshGroups())
.thenReturn(Futures.immediateFuture(ImmutableList.of()));
GetFileGroupsByFilterRequest getFileGroupsByFilterRequest =
GetFileGroupsByFilterRequest.newBuilder().setIncludeAllGroups(true).build();
List<ClientFileGroup> clientFileGroups =
mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get();
assertThat(clientFileGroups).isEmpty();
getFileGroupsByFilterRequest =
GetFileGroupsByFilterRequest.newBuilder()
.setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1))
.build();
clientFileGroups = mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get();
assertThat(clientFileGroups).isEmpty();
verifyNoInteractions(mockEventLogger);
}
@Test
public void getFileGroupsByFilter_withAccount() throws Exception {
List<Pair<GroupKey, DataFileGroupInternal>> keyDataFileGroupList = new ArrayList<>();
Account account1 = AccountUtil.create("account-name-1", "account-type");
Account account2 = AccountUtil.create("account-name-2", "account-type");
DataFileGroupInternal downloadedFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setAccount(AccountUtil.serialize(account1))
.build();
when(mockMobileDataDownloadManager.getFileGroup(groupKey, true))
.thenReturn(Futures.immediateFuture(downloadedFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(
downloadedFileGroup.getFile(0), downloadedFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
keyDataFileGroupList.add(
Pair.create(groupKey.toBuilder().setDownloaded(true).build(), downloadedFileGroup));
DataFileGroupInternal pendingFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
7 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_2},
new String[] {FILE_CHECKSUM_2},
new String[] {FILE_URL_2},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
when(mockMobileDataDownloadManager.getFileGroup(groupKey, false))
.thenReturn(Futures.immediateFuture(pendingFileGroup));
keyDataFileGroupList.add(
Pair.create(groupKey.toBuilder().setDownloaded(false).build(), pendingFileGroup));
DataFileGroupInternal pendingFileGroup2 =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
4 /* versionNumber */,
new String[] {FILE_ID_1, FILE_ID_2},
new int[] {FILE_SIZE_1, FILE_SIZE_2},
new String[] {FILE_CHECKSUM_1, FILE_CHECKSUM_2},
new String[] {FILE_URL_1, FILE_URL_2},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
GroupKey groupKey2 =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setAccount(AccountUtil.serialize(account2))
.build();
when(mockMobileDataDownloadManager.getFileGroup(groupKey2, false))
.thenReturn(Futures.immediateFuture(pendingFileGroup2));
keyDataFileGroupList.add(
Pair.create(groupKey2.toBuilder().setDownloaded(false).build(), pendingFileGroup2));
when(mockMobileDataDownloadManager.getAllFreshGroups())
.thenReturn(Futures.immediateFuture(keyDataFileGroupList));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
// We should get back 2 groups for FILE_GROUP_NAME_1 with account1.
GetFileGroupsByFilterRequest getFileGroupsByFilterRequest =
GetFileGroupsByFilterRequest.newBuilder()
.setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1))
.setAccountOptional(Optional.of(account1))
.build();
ImmutableList<ClientFileGroup> clientFileGroups =
mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get();
assertThat(clientFileGroups).hasSize(2);
ClientFileGroup downloadedClientFileGroup = clientFileGroups.get(0);
assertThat(downloadedClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(downloadedClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(downloadedClientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(downloadedClientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account1));
assertThat(downloadedClientFileGroup.getStatus()).isEqualTo(Status.DOWNLOADED);
assertThat(downloadedClientFileGroup.getFileCount()).isEqualTo(1);
ClientFile clientFile = downloadedClientFileGroup.getFileList().get(0);
assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1);
assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString());
assertThat(clientFile.getFullSizeInBytes()).isEqualTo(FILE_SIZE_1);
ClientFileGroup pendingClientFileGroup = clientFileGroups.get(1);
assertThat(pendingClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(pendingClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(pendingClientFileGroup.getVersionNumber()).isEqualTo(7);
assertThat(pendingClientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account1));
assertThat(pendingClientFileGroup.getStatus()).isEqualTo(Status.PENDING);
assertThat(pendingClientFileGroup.getFileCount()).isEqualTo(1);
clientFile = pendingClientFileGroup.getFileList().get(0);
assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1);
assertThat(clientFile.getFileUri()).isEmpty();
// We should get back 1 group for FILE_GROUP_NAME_1 with account2.
getFileGroupsByFilterRequest =
GetFileGroupsByFilterRequest.newBuilder()
.setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1))
.setAccountOptional(Optional.of(account2))
.build();
clientFileGroups = mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get();
ClientFileGroup pendingClientFileGroup2 = clientFileGroups.get(0);
assertThat(pendingClientFileGroup2.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(pendingClientFileGroup2.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(pendingClientFileGroup2.getVersionNumber()).isEqualTo(4);
assertThat(pendingClientFileGroup2.getAccount()).isEqualTo(AccountUtil.serialize(account2));
assertThat(pendingClientFileGroup2.getStatus()).isEqualTo(Status.PENDING);
assertThat(pendingClientFileGroup2.getFileCount()).isEqualTo(2);
}
@Test
public void getFileGroupsByFilter_groupWithNoAccountOnly() throws Exception {
List<Pair<GroupKey, DataFileGroupInternal>> keyDataFileGroupList = new ArrayList<>();
Account account1 = AccountUtil.create("account-name-1", "account-type");
Account account2 = AccountUtil.create("account-name-2", "account-type");
// downloadedFileGroup is associated with account1.
DataFileGroupInternal downloadedFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
/*versionNumber=*/ 5,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
GroupKey groupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setAccount(AccountUtil.serialize(account1))
.build();
when(mockMobileDataDownloadManager.getFileGroup(groupKey, true))
.thenReturn(Futures.immediateFuture(downloadedFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(
downloadedFileGroup.getFile(0), downloadedFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
keyDataFileGroupList.add(
Pair.create(groupKey.toBuilder().setDownloaded(true).build(), downloadedFileGroup));
// pendingFileGroup is associated with account2.
DataFileGroupInternal pendingFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
/*versionNumber=*/ 7,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_2},
new String[] {FILE_CHECKSUM_2},
new String[] {FILE_URL_2},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
GroupKey groupKey2 =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setAccount(AccountUtil.serialize(account2))
.build();
when(mockMobileDataDownloadManager.getFileGroup(groupKey2, false))
.thenReturn(Futures.immediateFuture(pendingFileGroup));
keyDataFileGroupList.add(
Pair.create(groupKey2.toBuilder().setDownloaded(false).build(), pendingFileGroup));
// pendingFileGroup2 is an account independent group.
DataFileGroupInternal pendingFileGroup2 =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
/*versionNumber=*/ 4,
new String[] {FILE_ID_1, FILE_ID_2},
new int[] {FILE_SIZE_1, FILE_SIZE_2},
new String[] {FILE_CHECKSUM_1, FILE_CHECKSUM_2},
new String[] {FILE_URL_1, FILE_URL_2},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
GroupKey groupKey3 =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.build();
when(mockMobileDataDownloadManager.getFileGroup(groupKey3, false))
.thenReturn(Futures.immediateFuture(pendingFileGroup2));
keyDataFileGroupList.add(
Pair.create(groupKey3.toBuilder().setDownloaded(false).build(), pendingFileGroup2));
when(mockMobileDataDownloadManager.getAllFreshGroups())
.thenReturn(Futures.immediateFuture(keyDataFileGroupList));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/*fileGroupPopulatorList=*/ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
/*downloadMonitorOptional=*/ Optional.absent(),
/* foregroundDownloadServiceClassOptional = */ Optional.absent(),
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
// We should get back only 1 group for FILE_GROUP_NAME_1 with groupWithNoAccountOnly being set
// to true.
GetFileGroupsByFilterRequest getFileGroupsByFilterRequest =
GetFileGroupsByFilterRequest.newBuilder()
.setGroupWithNoAccountOnly(true)
.setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1))
.build();
ImmutableList<ClientFileGroup> clientFileGroups =
mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get();
assertThat(clientFileGroups).hasSize(1);
ClientFileGroup pendingClientFileGroup = clientFileGroups.get(0);
assertThat(pendingClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(pendingClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(pendingClientFileGroup.getVersionNumber()).isEqualTo(4);
assertThat(pendingClientFileGroup.getStatus()).isEqualTo(Status.PENDING);
assertThat(pendingClientFileGroup.getFileCount()).isEqualTo(2);
assertThat(pendingClientFileGroup.hasAccount()).isFalse();
}
@Test
public void importFiles_whenSuccessful_returns() throws Exception {
String inlineFileUrl = String.format("inlinefile:sha1:%s", FILE_CHECKSUM_1);
DataFile inlineFile =
DataFile.newBuilder()
.setFileId(FILE_ID_1)
.setByteSize(FILE_SIZE_1)
.setChecksum(FILE_CHECKSUM_1)
.setUrlToDownload(inlineFileUrl)
.build();
ImmutableList<DataFile> updatedDataFileList = ImmutableList.of(inlineFile);
ImmutableMap<String, FileSource> inlineFileMap =
ImmutableMap.of(
FILE_ID_1, FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT")));
// TODO: rely on actual implementation once feature is fully implemented.
when(mockMobileDataDownloadManager.importFiles(
any(), anyLong(), any(), any(), any(), any(), any()))
.thenReturn(Futures.immediateVoidFuture());
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()),
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
// Since we use mocks, just call the method directly, no need to call addFileGroup first
mobileDataDownload
.importFiles(
ImportFilesRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setBuildId(1)
.setVariantId("testvariant")
.setUpdatedDataFileList(updatedDataFileList)
.setInlineFileMap(inlineFileMap)
.build())
.get();
// Verify mocks were called
GroupKey expectedGroupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.build();
ImmutableList<MetadataProto.DataFile> expectedDataFileList =
ImmutableList.of(ProtoConversionUtil.convertDataFile(inlineFile));
verify(mockMobileDataDownloadManager)
.importFiles(
eq(expectedGroupKey),
eq(1L),
eq("testvariant"),
eq(expectedDataFileList),
eq(inlineFileMap),
eq(Optional.absent()),
any());
}
@Test
public void importFiles_whenAccountIsSpecified_usesAccount() throws Exception {
Account account = AccountUtil.create("account-name", "account-type");
String inlineFileUrl = String.format("inlinefile:sha1:%s", FILE_CHECKSUM_1);
DataFile inlineFile =
DataFile.newBuilder()
.setFileId(FILE_ID_1)
.setByteSize(FILE_SIZE_1)
.setChecksum(FILE_CHECKSUM_1)
.setUrlToDownload(inlineFileUrl)
.build();
ImmutableList<DataFile> updatedDataFileList = ImmutableList.of(inlineFile);
ImmutableMap<String, FileSource> inlineFileMap =
ImmutableMap.of(
FILE_ID_1, FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT")));
// TODO: rely on actual implementation once feature is fully implemented.
when(mockMobileDataDownloadManager.importFiles(
any(), anyLong(), any(), any(), any(), any(), any()))
.thenReturn(Futures.immediateVoidFuture());
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()),
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
// Since we use mocks, just call the method directly, no need to call addFileGroup first
mobileDataDownload
.importFiles(
ImportFilesRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setAccountOptional(Optional.of(account))
.setBuildId(1)
.setVariantId("testvariant")
.setUpdatedDataFileList(updatedDataFileList)
.setInlineFileMap(inlineFileMap)
.build())
.get();
// Verify mocks were called
GroupKey expectedGroupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setAccount(AccountUtil.serialize(account))
.setOwnerPackage(context.getPackageName())
.build();
ImmutableList<MetadataProto.DataFile> expectedDataFileList =
ImmutableList.of(ProtoConversionUtil.convertDataFile(inlineFile));
verify(mockMobileDataDownloadManager)
.importFiles(
eq(expectedGroupKey),
eq(1L),
eq("testvariant"),
eq(expectedDataFileList),
eq(inlineFileMap),
eq(Optional.absent()),
any());
}
@Test
public void importFiles_whenFails_returnsFailure() throws Exception {
String inlineFileUrl = String.format("inlinefile:%s", FILE_CHECKSUM_1);
DataFile inlineFile =
DataFile.newBuilder()
.setFileId(FILE_ID_1)
.setByteSize(FILE_SIZE_1)
.setChecksum(FILE_CHECKSUM_1)
.setUrlToDownload(inlineFileUrl)
.build();
ImmutableList<DataFile> updatedDataFileList = ImmutableList.of(inlineFile);
ImmutableMap<String, FileSource> inlineFileMap =
ImmutableMap.of(
FILE_ID_1, FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT")));
// TODO: rely on actual implementation once feature is fully implemented.
when(mockMobileDataDownloadManager.importFiles(
any(), anyLong(), any(), any(), any(), any(), any()))
.thenReturn(Futures.immediateFailedFuture(new Exception("Test failure")));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()),
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
// Since we use mocks, just call the method directly, no need to call addFileGroup first
ExecutionException ex =
assertThrows(
ExecutionException.class,
() ->
mobileDataDownload
.importFiles(
ImportFilesRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setBuildId(1)
.setVariantId("testvariant")
.setUpdatedDataFileList(updatedDataFileList)
.setInlineFileMap(inlineFileMap)
.build())
.get());
assertThat(ex).hasMessageThat().contains("Test failure");
// Verify mocks were called
GroupKey expectedGroupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.build();
ImmutableList<MetadataProto.DataFile> expectedDataFileList =
ImmutableList.of(ProtoConversionUtil.convertDataFile(inlineFile));
verify(mockMobileDataDownloadManager)
.importFiles(
eq(expectedGroupKey),
eq(1L),
eq("testvariant"),
eq(expectedDataFileList),
eq(inlineFileMap),
eq(Optional.absent()),
any());
}
@Test
public void downloadFileGroup() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any()))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
CountDownLatch onCompleteLatch = new CountDownLatch(1);
ClientFileGroup clientFileGroup =
mobileDataDownload
.downloadFileGroup(
DownloadFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setListenerOptional(
Optional.of(
new DownloadListener() {
@Override
public void onProgress(long currentSize) {}
@Override
public void onComplete(ClientFileGroup clientFileGroup) {
assertThat(clientFileGroup.getGroupName())
.isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage())
.isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
// This is to verify that onComplete is called.
onCompleteLatch.countDown();
}
}))
.build())
.get();
// Verify that onComplete is called.
if (!onCompleteLatch.await(LATCH_WAIT_TIME_MS, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("onComplete is not called");
}
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
assertThat(clientFileGroup.hasAccount()).isFalse();
ClientFile clientFile = clientFileGroup.getFileList().get(0);
assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1);
assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString());
verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any());
verify(mockDownloadMonitor)
.addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class));
verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1));
assertThat(groupKeyCaptor.getValue().getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(groupKeyCaptor.getValue().hasAccount()).isFalse();
}
@Test
public void downloadFileGroup_failed() throws Exception {
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any()))
.thenReturn(
Futures.immediateFailedFuture(
DownloadException.builder()
.setDownloadResultCode(DownloadResultCode.UNKNOWN_ERROR)
.setMessage("Fail to download file group")
.build()));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ListenableFuture<ClientFileGroup> downloadFuture =
mobileDataDownload.downloadFileGroup(
DownloadFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setListenerOptional(
Optional.of(
new DownloadListener() {
@Override
public void onProgress(long currentSize) {}
@Override
public void onComplete(ClientFileGroup clientFileGroup) {}
}))
.build());
CountDownLatch onFailureLatch = new CountDownLatch(1);
Futures.addCallback(
downloadFuture,
new FutureCallback<ClientFileGroup>() {
@Override
public void onSuccess(ClientFileGroup result) {}
@Override
public void onFailure(Throwable t) {
// This is to ensure that onFailure is called.
onFailureLatch.countDown();
}
},
MoreExecutors.directExecutor());
assertThrows(ExecutionException.class, downloadFuture::get);
DownloadException e = LabsFutures.getFailureCauseAs(downloadFuture, DownloadException.class);
assertThat(e).hasMessageThat().contains("Fail");
if (!onFailureLatch.await(LATCH_WAIT_TIME_MS, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("latch timeout: onFailure is not called");
}
verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any());
verify(mockDownloadMonitor)
.addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class));
verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1));
assertThat(groupKeyCaptor.getValue().getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(groupKeyCaptor.getValue().hasAccount()).isFalse();
}
@Test
public void downloadFileGroup_withAccount() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any()))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
CountDownLatch onCompleteLatch = new CountDownLatch(1);
Account account = AccountUtil.create("account-name", "account-type");
ClientFileGroup clientFileGroup =
mobileDataDownload
.downloadFileGroup(
DownloadFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setAccountOptional(Optional.of(account))
.setListenerOptional(
Optional.of(
new DownloadListener() {
@Override
public void onProgress(long currentSize) {}
@Override
public void onComplete(ClientFileGroup clientFileGroup) {
assertThat(clientFileGroup.getGroupName())
.isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage())
.isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
// This is to verify that onComplete is called.
onCompleteLatch.countDown();
}
}))
.build())
.get();
// Verify that onComplete is called.
if (!onCompleteLatch.await(LATCH_WAIT_TIME_MS, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("onComplete is not called");
}
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account));
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
ClientFile clientFile = clientFileGroup.getFileList().get(0);
assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1);
assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString());
verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any());
verify(mockDownloadMonitor)
.addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class));
verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1));
assertThat(groupKeyCaptor.getValue().getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(groupKeyCaptor.getValue().getAccount()).isEqualTo(AccountUtil.serialize(account));
}
@Test
public void downloadFileGroup_withVariantId() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
/* versionNumber = */ 5,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI)
.toBuilder()
.setVariantId("en")
.build();
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any()))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ClientFileGroup clientFileGroup =
mobileDataDownload
.downloadFileGroup(
DownloadFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setVariantIdOptional(Optional.of("en"))
.build())
.get();
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getVariantId()).isEqualTo("en");
verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any());
GroupKey expectedGroupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setVariantId("en")
.build();
assertThat(groupKeyCaptor.getValue()).isEqualTo(expectedGroupKey);
}
@Test
public void downloadFileGroupWithForegroundService() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
/* versionNumber = */ 5,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any()))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), anyBoolean()))
.thenReturn(Futures.immediateFuture(dataFileGroup));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()),
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
CountDownLatch onCompleteLatch = new CountDownLatch(1);
ClientFileGroup clientFileGroup =
mobileDataDownload
.downloadFileGroupWithForegroundService(
DownloadFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setListenerOptional(
Optional.of(
new DownloadListener() {
@Override
public void onProgress(long currentSize) {}
@Override
public void onComplete(ClientFileGroup clientFileGroup) {
assertThat(clientFileGroup.getGroupName())
.isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage())
.isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
// This is to verify that onComplete is called.
onCompleteLatch.countDown();
}
}))
.build())
.get();
// Verify that onComplete is called.
if (!onCompleteLatch.await(LATCH_WAIT_TIME_MS, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("onComplete is not called");
}
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
assertThat(clientFileGroup.hasAccount()).isFalse();
ClientFile clientFile = clientFileGroup.getFileList().get(0);
assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1);
assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString());
verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any());
verify(mockDownloadMonitor)
.addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class));
verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1));
assertThat(groupKeyCaptor.getValue().getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(groupKeyCaptor.getValue().hasAccount()).isFalse();
}
@Test
public void downloadFileGroupWithForegroundService_failed() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
/* versionNumber = */ 5,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any()))
.thenReturn(
Futures.immediateFailedFuture(
DownloadException.builder()
.setDownloadResultCode(DownloadResultCode.UNKNOWN_ERROR)
.setMessage("Fail to download file group")
.build()));
when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(false)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(true)))
.thenReturn(Futures.immediateFuture(null));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ListenableFuture<ClientFileGroup> downloadFuture =
mobileDataDownload.downloadFileGroupWithForegroundService(
DownloadFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setListenerOptional(
Optional.of(
new DownloadListener() {
@Override
public void onProgress(long currentSize) {}
@Override
public void onComplete(ClientFileGroup clientFileGroup) {}
}))
.build());
CountDownLatch onFailureLatch = new CountDownLatch(1);
Futures.addCallback(
downloadFuture,
new FutureCallback<ClientFileGroup>() {
@Override
public void onSuccess(ClientFileGroup result) {}
@Override
public void onFailure(Throwable t) {
// This is to ensure that onFailure is called.
onFailureLatch.countDown();
}
},
MoreExecutors.directExecutor());
assertThrows(ExecutionException.class, downloadFuture::get);
DownloadException e = LabsFutures.getFailureCauseAs(downloadFuture, DownloadException.class);
assertThat(e).hasMessageThat().contains("Fail");
if (!onFailureLatch.await(LATCH_WAIT_TIME_MS, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("latch timeout: onFailure is not called");
}
verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any());
verify(mockDownloadMonitor)
.addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class));
// Sleep for 1 sec to wait for the listener.onFailure to finish.
Thread.sleep(/*millis=*/ 1000);
verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1));
assertThat(groupKeyCaptor.getValue().getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(groupKeyCaptor.getValue().hasAccount()).isFalse();
}
@Test
public void downloadFileGroupWithForegroundService_withAccount() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
5 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any()))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(false)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(true)))
.thenReturn(Futures.immediateFuture(null));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
CountDownLatch onCompleteLatch = new CountDownLatch(1);
Account account = AccountUtil.create("account-name", "account-type");
ClientFileGroup clientFileGroup =
mobileDataDownload
.downloadFileGroupWithForegroundService(
DownloadFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setAccountOptional(Optional.of(account))
.setListenerOptional(
Optional.of(
new DownloadListener() {
@Override
public void onProgress(long currentSize) {}
@Override
public void onComplete(ClientFileGroup clientFileGroup) {
assertThat(clientFileGroup.getGroupName())
.isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage())
.isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
// This is to verify that onComplete is called.
onCompleteLatch.countDown();
}
}))
.build())
.get();
// Verify that onComplete is called.
if (!onCompleteLatch.await(LATCH_WAIT_TIME_MS, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("onComplete is not called");
}
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account));
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
ClientFile clientFile = clientFileGroup.getFileList().get(0);
assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1);
assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString());
verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any());
verify(mockDownloadMonitor)
.addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class));
verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1));
assertThat(groupKeyCaptor.getValue().getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(groupKeyCaptor.getValue().getAccount()).isEqualTo(AccountUtil.serialize(account));
}
@Test
public void downloadFileGroupWithForegroundService_withVariantId() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
/* versionNumber = */ 5,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI)
.toBuilder()
.setVariantId("en")
.build();
ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class);
when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any()))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(false)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(true)))
.thenReturn(Futures.immediateFuture(null));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ClientFileGroup clientFileGroup =
mobileDataDownload
.downloadFileGroupWithForegroundService(
DownloadFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setVariantIdOptional(Optional.of("en"))
.build())
.get();
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getVariantId()).isEqualTo("en");
verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any());
GroupKey expectedGroupKey =
GroupKey.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setOwnerPackage(context.getPackageName())
.setVariantId("en")
.build();
assertThat(groupKeyCaptor.getValue()).isEqualTo(expectedGroupKey);
}
@Test
public void downloadFileGroupWithForegroundService_whenAlreadyDownloaded() throws Exception {
DataFileGroupInternal dataFileGroup =
createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
/* versionNumber = */ 5,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
// Mock situation: no pending group but there is a downloaded group
when(mockMobileDataDownloadManager.getFileGroup(any(), eq(false)))
.thenReturn(Futures.immediateFuture(null));
when(mockMobileDataDownloadManager.getFileGroup(any(), eq(true)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
CountDownLatch onCompleteLatch = new CountDownLatch(1);
ClientFileGroup clientFileGroup =
mobileDataDownload
.downloadFileGroupWithForegroundService(
DownloadFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setListenerOptional(
Optional.of(
new DownloadListener() {
@Override
public void onProgress(long currentSize) {}
@Override
public void onComplete(ClientFileGroup clientFileGroup) {
assertThat(clientFileGroup.getGroupName())
.isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage())
.isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
// This is to verify that onComplete is called.
onCompleteLatch.countDown();
}
}))
.build())
.get();
// Verify that onComplete is called.
if (!onCompleteLatch.await(LATCH_WAIT_TIME_MS, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("onComplete is not called");
}
assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName());
assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
assertThat(clientFileGroup.hasAccount()).isFalse();
ClientFile clientFile = clientFileGroup.getFileList().get(0);
assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1);
assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString());
verify(mockMobileDataDownloadManager, times(1)).getFileGroup(any(GroupKey.class), eq(true));
verify(mockMobileDataDownloadManager, times(1)).getFileGroup(any(GroupKey.class), eq(false));
verify(mockMobileDataDownloadManager, times(0))
.downloadFileGroup(any(GroupKey.class), any(), any());
verify(mockDownloadMonitor)
.addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class));
verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1));
}
@Test
public void downloadFileGroupWithForegroundService_whenNoVersionFound_fails() throws Exception {
when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), anyBoolean()))
.thenReturn(Futures.immediateFuture(null));
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
Optional.of(mockDownloadMonitor),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
CountDownLatch onFailureLatch = new CountDownLatch(1);
ListenableFuture<ClientFileGroup> downloadFuture =
mobileDataDownload.downloadFileGroupWithForegroundService(
DownloadFileGroupRequest.newBuilder()
.setGroupName(FILE_GROUP_NAME_1)
.setListenerOptional(
Optional.of(
new DownloadListener() {
@Override
public void onProgress(long currentSize) {}
@Override
public void onComplete(ClientFileGroup clientFileGroup) {
fail("onComplete should not be called");
}
@Override
public void onFailure(Throwable t) {
assertThat(t).isInstanceOf(DownloadException.class);
assertThat(((DownloadException) t).getDownloadResultCode())
.isEqualTo(DownloadResultCode.GROUP_NOT_FOUND_ERROR);
// This is to verify onFailure is called.
onFailureLatch.countDown();
}
}))
.build());
assertThrows(ExecutionException.class, downloadFuture::get);
// Verify onFailure is called
if (!onFailureLatch.await(LATCH_WAIT_TIME_MS, TimeUnit.MILLISECONDS)) {
fail("onFailure should be called");
}
DownloadException e = LabsFutures.getFailureCauseAs(downloadFuture, DownloadException.class);
assertThat(e.getDownloadResultCode()).isEqualTo(DownloadResultCode.GROUP_NOT_FOUND_ERROR);
// Verify did not attempt a download
verify(mockMobileDataDownloadManager, times(0))
.downloadFileGroup(any(GroupKey.class), any(), any());
verify(mockDownloadMonitor, times(0))
.addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class));
}
@Test
public void maintenance_success() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/*fileGroupPopulatorList=*/ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
/*downloadMonitorOptional=*/ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
when(mockMobileDataDownloadManager.maintenance()).thenReturn(Futures.immediateFuture(null));
mobileDataDownload.maintenance().get();
verify(mockMobileDataDownloadManager).maintenance();
verifyNoMoreInteractions(mockMobileDataDownloadManager);
}
@Test
public void maintenance_failure() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/*fileGroupPopulatorList=*/ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
/*downloadMonitorOptional=*/ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
when(mockMobileDataDownloadManager.maintenance())
.thenReturn(Futures.immediateFailedFuture(new IOException("test-failure")));
ExecutionException e =
assertThrows(ExecutionException.class, () -> mobileDataDownload.maintenance().get());
assertThat(e).hasCauseThat().isInstanceOf(IOException.class);
assertThat(e).hasCauseThat().hasMessageThat().isEqualTo("test-failure");
verify(mockMobileDataDownloadManager).maintenance();
verifyNoMoreInteractions(mockMobileDataDownloadManager);
}
@Test
public void schedulePeriodicTasks() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
mobileDataDownload.schedulePeriodicTasks();
verify(mockTaskScheduler)
.schedulePeriodicTask(
TaskScheduler.CHARGING_PERIODIC_TASK,
(new Flags() {}).chargingGcmTaskPeriod(),
NetworkState.NETWORK_STATE_ANY,
/* constraintOverrides = */ Optional.absent());
verify(mockTaskScheduler)
.schedulePeriodicTask(
TaskScheduler.MAINTENANCE_PERIODIC_TASK,
(new Flags() {}).maintenanceGcmTaskPeriod(),
NetworkState.NETWORK_STATE_ANY,
/* constraintOverrides = */ Optional.absent());
verify(mockTaskScheduler)
.schedulePeriodicTask(
TaskScheduler.CELLULAR_CHARGING_PERIODIC_TASK,
(new Flags() {}).cellularChargingGcmTaskPeriod(),
NetworkState.NETWORK_STATE_CONNECTED,
/* constraintOverrides = */ Optional.absent());
verify(mockTaskScheduler)
.schedulePeriodicTask(
TaskScheduler.WIFI_CHARGING_PERIODIC_TASK,
(new Flags() {}).wifiChargingGcmTaskPeriod(),
NetworkState.NETWORK_STATE_UNMETERED,
/* constraintOverrides = */ Optional.absent());
verifyNoMoreInteractions(mockTaskScheduler);
}
@Test
public void schedulePeriodicTasks_nullTaskScheduler() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
/* taskSchedulerOptional = */ Optional.absent(),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
mobileDataDownload.schedulePeriodicTasks();
verifyNoInteractions(mockTaskScheduler);
}
@Test
public void schedulePeriodicBackgroundTasks() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
mobileDataDownload.schedulePeriodicBackgroundTasks().get();
verify(mockTaskScheduler)
.schedulePeriodicTask(
TaskScheduler.CHARGING_PERIODIC_TASK,
(new Flags() {}).chargingGcmTaskPeriod(),
NetworkState.NETWORK_STATE_ANY,
/* constraintOverrides = */ Optional.absent());
verify(mockTaskScheduler)
.schedulePeriodicTask(
TaskScheduler.MAINTENANCE_PERIODIC_TASK,
(new Flags() {}).maintenanceGcmTaskPeriod(),
NetworkState.NETWORK_STATE_ANY,
/* constraintOverrides = */ Optional.absent());
verify(mockTaskScheduler)
.schedulePeriodicTask(
TaskScheduler.CELLULAR_CHARGING_PERIODIC_TASK,
(new Flags() {}).cellularChargingGcmTaskPeriod(),
NetworkState.NETWORK_STATE_CONNECTED,
/* constraintOverrides = */ Optional.absent());
verify(mockTaskScheduler)
.schedulePeriodicTask(
TaskScheduler.WIFI_CHARGING_PERIODIC_TASK,
(new Flags() {}).wifiChargingGcmTaskPeriod(),
NetworkState.NETWORK_STATE_UNMETERED,
/* constraintOverrides = */ Optional.absent());
verifyNoMoreInteractions(mockTaskScheduler);
}
@Test
public void schedulePeriodicBackgroundTasks_nullTaskScheduler() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
/* taskSchedulerOptional = */ Optional.absent(),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
mobileDataDownload.schedulePeriodicBackgroundTasks().get();
verifyNoInteractions(mockTaskScheduler);
}
@Test
public void schedulePeriodicBackgroundTasks_withConstraintOverrides() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ConstraintOverrides wifiOverrides =
ConstraintOverrides.newBuilder()
.setRequiresCharging(false)
.setRequiresDeviceIdle(true)
.build();
ConstraintOverrides cellularOverrides =
ConstraintOverrides.newBuilder()
.setRequiresCharging(true)
.setRequiresDeviceIdle(false)
.build();
Map<String, ConstraintOverrides> constraintOverridesMap = new HashMap<>();
constraintOverridesMap.put(TaskScheduler.WIFI_CHARGING_PERIODIC_TASK, wifiOverrides);
constraintOverridesMap.put(TaskScheduler.CELLULAR_CHARGING_PERIODIC_TASK, cellularOverrides);
mobileDataDownload.schedulePeriodicBackgroundTasks(Optional.of(constraintOverridesMap)).get();
verify(mockTaskScheduler)
.schedulePeriodicTask(
TaskScheduler.CHARGING_PERIODIC_TASK,
(new Flags() {}).chargingGcmTaskPeriod(),
NetworkState.NETWORK_STATE_ANY,
Optional.absent());
verify(mockTaskScheduler)
.schedulePeriodicTask(
TaskScheduler.MAINTENANCE_PERIODIC_TASK,
(new Flags() {}).maintenanceGcmTaskPeriod(),
NetworkState.NETWORK_STATE_ANY,
Optional.absent());
verify(mockTaskScheduler)
.schedulePeriodicTask(
TaskScheduler.CELLULAR_CHARGING_PERIODIC_TASK,
(new Flags() {}).cellularChargingGcmTaskPeriod(),
NetworkState.NETWORK_STATE_CONNECTED,
Optional.of(cellularOverrides));
verify(mockTaskScheduler)
.schedulePeriodicTask(
TaskScheduler.WIFI_CHARGING_PERIODIC_TASK,
(new Flags() {}).wifiChargingGcmTaskPeriod(),
NetworkState.NETWORK_STATE_UNMETERED,
Optional.of(wifiOverrides));
verifyNoMoreInteractions(mockTaskScheduler);
}
@Test
public void schedulePeriodicBackgroundTasks_nullTaskScheduler_andOverrides() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
/* taskSchedulerOptional = */ Optional.absent(),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
mobileDataDownload.schedulePeriodicBackgroundTasks(Optional.absent()).get();
verifyNoInteractions(mockTaskScheduler);
}
// A helper function to create a DataFilegroup.
private static DataFileGroup createDataFileGroup(
String groupName,
String ownerPackage,
int versionNumber,
String[] fileId,
int[] byteSize,
String[] checksum,
String[] url,
DeviceNetworkPolicy deviceNetworkPolicy) {
if (fileId.length != byteSize.length
|| fileId.length != checksum.length
|| fileId.length != url.length) {
throw new IllegalArgumentException();
}
DataFileGroup.Builder dataFileGroupBuilder =
DataFileGroup.newBuilder()
.setGroupName(groupName)
.setOwnerPackage(ownerPackage)
.setFileGroupVersionNumber(versionNumber)
.setDownloadConditions(
DownloadConditions.newBuilder().setDeviceNetworkPolicy(deviceNetworkPolicy));
for (int i = 0; i < fileId.length; ++i) {
DataFile file =
DataFile.newBuilder()
.setFileId(fileId[i])
.setByteSize(byteSize[i])
.setChecksum(checksum[i])
.setUrlToDownload(url[i])
.build();
dataFileGroupBuilder.addFile(file);
}
return dataFileGroupBuilder.build();
}
private static DataFileGroupInternal createDataFileGroupInternal(
String groupName,
String ownerPackage,
int versionNumber,
String[] fileId,
int[] byteSize,
String[] checksum,
String[] url,
DeviceNetworkPolicy deviceNetworkPolicy)
throws Exception {
return ProtoConversionUtil.convert(
createDataFileGroup(
groupName,
ownerPackage,
versionNumber,
fileId,
byteSize,
checksum,
url,
deviceNetworkPolicy));
}
@Test
public void handleTask_maintenance() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
when(mockMobileDataDownloadManager.maintenance()).thenReturn(Futures.immediateFuture(null));
mobileDataDownload.handleTask(TaskScheduler.MAINTENANCE_PERIODIC_TASK).get();
verify(mockMobileDataDownloadManager).maintenance();
verifyNoMoreInteractions(mockMobileDataDownloadManager);
}
@Test
public void handleTask_charging() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of(mockFileGroupPopulator),
Optional.of(mockTaskScheduler),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
when(mockMobileDataDownloadManager.verifyAllPendingGroups(any()))
.thenReturn(Futures.immediateFuture(null));
when(mockFileGroupPopulator.refreshFileGroups(mobileDataDownload))
.thenReturn(Futures.immediateFuture(null));
mobileDataDownload.handleTask(TaskScheduler.CHARGING_PERIODIC_TASK).get();
verify(mockFileGroupPopulator).refreshFileGroups(mobileDataDownload);
verify(mockMobileDataDownloadManager).verifyAllPendingGroups(any());
verifyNoMoreInteractions(mockMobileDataDownloadManager);
}
@Test
public void handleTask_wifi_charging() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of(mockFileGroupPopulator),
Optional.of(mockTaskScheduler),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
when(mockFileGroupPopulator.refreshFileGroups(mobileDataDownload))
.thenReturn(Futures.immediateFuture(null));
when(mockMobileDataDownloadManager.downloadAllPendingGroups(eq(true) /*wifi*/, any()))
.thenReturn(Futures.immediateFuture(null));
mobileDataDownload.handleTask(TaskScheduler.WIFI_CHARGING_PERIODIC_TASK).get();
verify(mockFileGroupPopulator, times(2)).refreshFileGroups(mobileDataDownload);
verify(mockMobileDataDownloadManager, times(2)).downloadAllPendingGroups(eq(true), any());
verifyNoMoreInteractions(mockMobileDataDownloadManager);
}
@Test
public void handleTask_cellular_charging() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of(mockFileGroupPopulator),
Optional.of(mockTaskScheduler),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
when(mockFileGroupPopulator.refreshFileGroups(mobileDataDownload))
.thenReturn(Futures.immediateFuture(null));
when(mockMobileDataDownloadManager.downloadAllPendingGroups(eq(false) /*wifi*/, any()))
.thenReturn(Futures.immediateFuture(null));
mobileDataDownload.handleTask(TaskScheduler.CELLULAR_CHARGING_PERIODIC_TASK).get();
verify(mockFileGroupPopulator, times(2)).refreshFileGroups(mobileDataDownload);
verify(mockMobileDataDownloadManager, times(2)).downloadAllPendingGroups(eq(false), any());
verifyNoMoreInteractions(mockMobileDataDownloadManager);
}
@Test
public void handleTask_no_filegroup_populator() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
/* fileGroupPopulatorList = */ ImmutableList.of(),
Optional.of(mockTaskScheduler),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
when(mockMobileDataDownloadManager.verifyAllPendingGroups(any()))
.thenReturn(Futures.immediateFuture(null));
when(mockMobileDataDownloadManager.downloadAllPendingGroups(anyBoolean() /*wifi*/, any()))
.thenReturn(Futures.immediateFuture(null));
mobileDataDownload.handleTask(TaskScheduler.CHARGING_PERIODIC_TASK).get();
verify(mockMobileDataDownloadManager).verifyAllPendingGroups(any());
mobileDataDownload.handleTask(TaskScheduler.CELLULAR_CHARGING_PERIODIC_TASK).get();
verify(mockMobileDataDownloadManager, times(2)).downloadAllPendingGroups(eq(false), any());
mobileDataDownload.handleTask(TaskScheduler.WIFI_CHARGING_PERIODIC_TASK).get();
verify(mockMobileDataDownloadManager, times(2)).downloadAllPendingGroups(eq(true), any());
}
@Test
public void handleTask_invalid_tag() throws Exception {
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of(mockFileGroupPopulator),
Optional.of(mockTaskScheduler),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
ExecutionException e =
assertThrows(
ExecutionException.class, () -> mobileDataDownload.handleTask("invalid-tag").get());
assertThat(e).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
}
@Test
public void handleTask_onePopulatorFails_continuesToRunOthers() throws Exception {
FileGroupPopulator failingPopulator =
(MobileDataDownload unused) ->
Futures.immediateFailedFuture(new IllegalArgumentException("test"));
AtomicBoolean refreshedOneSucceedingPopulator = new AtomicBoolean(false);
FileGroupPopulator oneSucceedingPopulator =
(MobileDataDownload unused) -> {
refreshedOneSucceedingPopulator.set(true);
return Futures.immediateVoidFuture();
};
AtomicBoolean refreshedAnotherSucceedingPopulator = new AtomicBoolean(false);
FileGroupPopulator anotherSucceedingPopulator =
(MobileDataDownload unused) -> {
refreshedAnotherSucceedingPopulator.set(true);
return Futures.immediateVoidFuture();
};
// The populators will be executed in this order.
ImmutableList<FileGroupPopulator> populators =
ImmutableList.of(failingPopulator, oneSucceedingPopulator, anotherSucceedingPopulator);
MobileDataDownload mobileDataDownload =
new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
populators,
Optional.of(mockTaskScheduler),
fileStorage,
/* downloadMonitorOptional = */ Optional.absent(),
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
when(mockMobileDataDownloadManager.verifyAllPendingGroups(any() /* validator */))
.thenReturn(Futures.immediateVoidFuture());
when(mockMobileDataDownloadManager.downloadAllPendingGroups(
anyBoolean() /*wifi*/, any() /* validator */))
.thenReturn(Futures.immediateVoidFuture());
ListenableFuture<Void> handleFuture =
mobileDataDownload.handleTask(TaskScheduler.WIFI_CHARGING_PERIODIC_TASK);
assertThat(handleFuture).whenDone().isSuccessful();
handleFuture.get();
assertThat(refreshedOneSucceedingPopulator.get()).isTrue();
assertThat(refreshedAnotherSucceedingPopulator.get()).isTrue();
}
@Test
public void reportUsage_basic() throws Exception {
DataFileGroupInternal dataFileGroup = createDefaultDataFileGroupInternal();
when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true)))
.thenReturn(Futures.immediateFuture(dataFileGroup));
when(mockMobileDataDownloadManager.getDataFileUri(dataFileGroup.getFile(0), dataFileGroup))
.thenReturn(Futures.immediateFuture(onDeviceUri1));
MobileDataDownload mobileDataDownload = createDefaultMobileDataDownload();
ClientFileGroup clientFileGroup =
mobileDataDownload
.getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build())
.get();
UsageEvent usageEvent =
UsageEvent.builder()
.setEventCode(0)
.setAppVersion(123)
.setClientFileGroup(clientFileGroup)
.build();
mobileDataDownload.reportUsage(usageEvent).get();
verify(mockEventLogger).logMddUsageEvent(createFileGroupStats(clientFileGroup), null);
}
private static Void createFileGroupStats(ClientFileGroup clientFileGroup) {
return null;
}
private MobileDataDownload createDefaultMobileDataDownload() {
return new MobileDataDownloadImpl(
context,
mockEventLogger,
mockMobileDataDownloadManager,
EXECUTOR,
ImmutableList.of() /* fileGroupPopulatorList */,
Optional.of(mockTaskScheduler),
fileStorage,
Optional.absent() /* downloadMonitorOptional */,
Optional.of(this.getClass()), // don't need to use the real foreground download service.
flags,
singleFileDownloader,
Optional.absent() /* customFileGroupValidator */);
}
private DataFileGroupInternal createDefaultDataFileGroupInternal() throws Exception {
return createDataFileGroupInternal(
FILE_GROUP_NAME_1,
context.getPackageName(),
1 /* versionNumber */,
new String[] {FILE_ID_1},
new int[] {FILE_SIZE_1},
new String[] {FILE_CHECKSUM_1},
new String[] {FILE_URL_1},
DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
}
}