1 /* 2 * Copyright 2022 Google LLC 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.android.libraries.mobiledatadownload; 17 18 import static com.google.common.labs.truth.FutureSubject.assertThat; 19 import static com.google.common.truth.Truth.assertThat; 20 import static java.nio.charset.StandardCharsets.UTF_8; 21 import static org.junit.Assert.assertNull; 22 import static org.junit.Assert.assertThrows; 23 import static org.junit.Assert.fail; 24 import static org.mockito.ArgumentMatchers.any; 25 import static org.mockito.ArgumentMatchers.anyBoolean; 26 import static org.mockito.ArgumentMatchers.anyList; 27 import static org.mockito.ArgumentMatchers.anyLong; 28 import static org.mockito.Mockito.doThrow; 29 import static org.mockito.Mockito.eq; 30 import static org.mockito.Mockito.never; 31 import static org.mockito.Mockito.times; 32 import static org.mockito.Mockito.verify; 33 import static org.mockito.Mockito.verifyNoInteractions; 34 import static org.mockito.Mockito.verifyNoMoreInteractions; 35 import static org.mockito.Mockito.when; 36 37 import android.accounts.Account; 38 import android.content.Context; 39 import android.net.Uri; 40 import androidx.test.core.app.ApplicationProvider; 41 import com.google.android.libraries.mobiledatadownload.DownloadException.DownloadResultCode; 42 import com.google.android.libraries.mobiledatadownload.TaskScheduler.ConstraintOverrides; 43 import com.google.android.libraries.mobiledatadownload.TaskScheduler.NetworkState; 44 import com.google.android.libraries.mobiledatadownload.account.AccountUtil; 45 import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage; 46 import com.google.android.libraries.mobiledatadownload.file.backends.AndroidFileBackend; 47 import com.google.android.libraries.mobiledatadownload.file.openers.WriteStreamOpener; 48 import com.google.android.libraries.mobiledatadownload.internal.MobileDataDownloadManager; 49 import com.google.android.libraries.mobiledatadownload.internal.collect.GroupKeyAndGroup; 50 import com.google.android.libraries.mobiledatadownload.internal.logging.EventLogger; 51 import com.google.android.libraries.mobiledatadownload.internal.logging.testing.FakeEventLogger; 52 import com.google.android.libraries.mobiledatadownload.internal.util.ProtoConversionUtil; 53 import com.google.android.libraries.mobiledatadownload.lite.Downloader; 54 import com.google.android.libraries.mobiledatadownload.monitor.DownloadProgressMonitor; 55 import com.google.android.libraries.mobiledatadownload.testing.FakeTimeSource; 56 import com.google.android.libraries.mobiledatadownload.testing.TestFlags; 57 import com.google.common.base.Optional; 58 import com.google.common.collect.ImmutableList; 59 import com.google.common.collect.ImmutableMap; 60 import com.google.common.labs.concurrent.LabsFutures; 61 import com.google.common.util.concurrent.FutureCallback; 62 import com.google.common.util.concurrent.Futures; 63 import com.google.common.util.concurrent.ListenableFuture; 64 import com.google.common.util.concurrent.ListeningExecutorService; 65 import com.google.common.util.concurrent.MoreExecutors; 66 import com.google.mobiledatadownload.ClientConfigProto.ClientFile; 67 import com.google.mobiledatadownload.ClientConfigProto.ClientFileGroup; 68 import com.google.mobiledatadownload.ClientConfigProto.ClientFileGroup.Status; 69 import com.google.mobiledatadownload.DownloadConfigProto.DataFile; 70 import com.google.mobiledatadownload.DownloadConfigProto.DataFileGroup; 71 import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions; 72 import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions.DeviceNetworkPolicy; 73 import com.google.mobiledatadownload.LogProto.DataDownloadFileGroupStats; 74 import com.google.mobiledatadownload.internal.MetadataProto; 75 import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupInternal; 76 import com.google.mobiledatadownload.internal.MetadataProto.GroupKey; 77 import com.google.protobuf.Any; 78 import com.google.protobuf.ByteString; 79 import com.google.protobuf.StringValue; 80 import java.io.IOException; 81 import java.io.OutputStream; 82 import java.util.ArrayList; 83 import java.util.HashMap; 84 import java.util.List; 85 import java.util.Map; 86 import java.util.concurrent.CancellationException; 87 import java.util.concurrent.ExecutionException; 88 import java.util.concurrent.Executors; 89 import java.util.concurrent.TimeUnit; 90 import java.util.concurrent.atomic.AtomicBoolean; 91 import org.junit.After; 92 import org.junit.Before; 93 import org.junit.Rule; 94 import org.junit.Test; 95 import org.junit.runner.RunWith; 96 import org.mockito.ArgumentCaptor; 97 import org.mockito.Captor; 98 import org.mockito.Mock; 99 import org.mockito.junit.MockitoJUnit; 100 import org.mockito.junit.MockitoRule; 101 import org.robolectric.RobolectricTestRunner; 102 103 /** Tests for {@link com.google.android.libraries.mobiledatadownload.MobileDataDownload}. */ 104 @RunWith(RobolectricTestRunner.class) 105 public class MobileDataDownloadTest { 106 private static final Context context = ApplicationProvider.getApplicationContext(); 107 108 private static final String FILE_GROUP_NAME_1 = "test-group-1"; 109 private static final String FILE_GROUP_NAME_2 = "test-group-2"; 110 private static final String FILE_ID_1 = "test-file-1"; 111 private static final String FILE_ID_2 = "test-file-2"; 112 private static final String FILE_CHECKSUM_1 = "c1ef7864c76a99ae738ddad33882ed65972c99cc"; 113 private static final String FILE_URL_1 = "https://www.gstatic.com/suggest-dev/odws1_test_4.jar"; 114 private static final int FILE_SIZE_1 = 85769; 115 116 private static final String FILE_CHECKSUM_2 = "a1cba9d87b1440f41ce9e7da38c43e1f6bd7d5df"; 117 private static final String FILE_URL_2 = "https://www.gstatic.com/suggest-dev/odws1_empty.jar"; 118 private static final int FILE_SIZE_2 = 554; 119 120 private static final DataFileGroup FILE_GROUP_1 = 121 createDataFileGroup( 122 FILE_GROUP_NAME_1, 123 context.getPackageName(), 124 /* versionNumber= */ 1, 125 new String[] {FILE_ID_1}, 126 new int[] {FILE_SIZE_1}, 127 new String[] {FILE_CHECKSUM_1}, 128 new String[] {FILE_URL_1}, 129 DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI); 130 131 private static final DataFileGroupInternal FILE_GROUP_INTERNAL_1 = 132 createDataFileGroupInternal( 133 FILE_GROUP_NAME_1, 134 context.getPackageName(), 135 /* versionNumber= */ 5, 136 new String[] {FILE_ID_1}, 137 new int[] {FILE_SIZE_1}, 138 new String[] {FILE_CHECKSUM_1}, 139 new String[] {FILE_URL_1}, 140 DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI); 141 142 private final Uri onDeviceUri1 = 143 Uri.parse( 144 "android://com.google.android.libraries.mobiledatadownload/files/datadownload/shared/public/file_1"); 145 private final Uri onDeviceDirUri = 146 Uri.parse( 147 "android://com.google.android.libraries.mobiledatadownload/files/datadownload/shared/public/dir"); 148 private final Uri onDeviceDirFileUri1 = 149 Uri.parse( 150 "android://com.google.android.libraries.mobiledatadownload/files/datadownload/shared/public/dir/file_1"); 151 private final String onDeviceDirFile1Content = "Test file 1."; 152 private final Uri onDeviceDirFileUri2 = 153 Uri.parse( 154 "android://com.google.android.libraries.mobiledatadownload/files/datadownload/shared/public/dir/file_2"); 155 private final String onDeviceDirFile2Content = "Test file 2."; 156 private final Uri onDeviceDirFileUri3 = 157 Uri.parse( 158 "android://com.google.android.libraries.mobiledatadownload/files/datadownload/shared/public/dir/sub/file"); 159 private final String onDeviceDirFile3Content = "Test file 3 in sub-dir."; 160 161 private final TestFlags flags = new TestFlags(); 162 private SynchronousFileStorage fileStorage; 163 private FakeTimeSource timeSource; 164 private FakeEventLogger fakeEventLogger; 165 166 @Mock EventLogger mockEventLogger; 167 @Mock MobileDataDownloadManager mockMobileDataDownloadManager; 168 @Mock TaskScheduler mockTaskScheduler; 169 @Mock FileGroupPopulator mockFileGroupPopulator; 170 @Mock DownloadProgressMonitor mockDownloadMonitor; 171 @Mock Downloader singleFileDownloader; 172 173 @Captor ArgumentCaptor<GroupKey> groupKeyCaptor; 174 @Captor ArgumentCaptor<List<GroupKey>> groupKeysCaptor; 175 176 // Note: Executor must not be a single thread executor. 177 ListeningExecutorService controlExecutor = 178 MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()); 179 180 @Rule public final MockitoRule mocks = MockitoJUnit.rule(); 181 182 @Before setUp()183 public void setUp() throws IOException { 184 fileStorage = 185 new SynchronousFileStorage( 186 ImmutableList.of(AndroidFileBackend.builder(context).build()) /*backends*/); 187 createFile(onDeviceUri1, "test"); 188 if (!fileStorage.exists(onDeviceDirUri)) { 189 fileStorage.createDirectory(onDeviceDirUri); 190 } 191 createFile(onDeviceDirFileUri1, onDeviceDirFile1Content); 192 createFile(onDeviceDirFileUri2, onDeviceDirFile2Content); 193 createFile(onDeviceDirFileUri3, onDeviceDirFile3Content); 194 timeSource = new FakeTimeSource(); 195 fakeEventLogger = new FakeEventLogger(); 196 } 197 198 @After tearDown()199 public void tearDown() throws Exception { 200 if (fileStorage.exists(onDeviceUri1)) { 201 fileStorage.deleteFile(onDeviceUri1); 202 } 203 if (fileStorage.exists(onDeviceDirFileUri1)) { 204 fileStorage.deleteFile(onDeviceDirFileUri1); 205 } 206 if (fileStorage.exists(onDeviceDirFileUri2)) { 207 fileStorage.deleteFile(onDeviceDirFileUri2); 208 } 209 if (fileStorage.exists(onDeviceDirFileUri3)) { 210 fileStorage.deleteFile(onDeviceDirFileUri3); 211 } 212 } 213 createFile(Uri uri, String content)214 private void createFile(Uri uri, String content) throws IOException { 215 try (OutputStream out = fileStorage.open(uri, WriteStreamOpener.create())) { 216 out.write(content.getBytes(UTF_8)); 217 } 218 } 219 expectErrorLogMessage(String message)220 private void expectErrorLogMessage(String message) {} 221 222 @Test buildGetFileGroupsByFilterRequest()223 public void buildGetFileGroupsByFilterRequest() throws Exception { 224 Account account = AccountUtil.create("account-name", "account-type"); 225 GetFileGroupsByFilterRequest request1 = 226 GetFileGroupsByFilterRequest.newBuilder() 227 .setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1)) 228 .setAccountOptional(Optional.of(account)) 229 .build(); 230 assertThat(request1.groupNameOptional()).hasValue(FILE_GROUP_NAME_1); 231 assertThat(request1.accountOptional()).hasValue(account); 232 233 GetFileGroupsByFilterRequest request2 = 234 GetFileGroupsByFilterRequest.newBuilder() 235 .setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1)) 236 .build(); 237 assertThat(request2.groupNameOptional()).hasValue(FILE_GROUP_NAME_1); 238 assertThat(request2.accountOptional()).isAbsent(); 239 240 GetFileGroupsByFilterRequest.Builder builder = GetFileGroupsByFilterRequest.newBuilder(); 241 242 assertThrows(IllegalArgumentException.class, builder::build); 243 } 244 245 @Test buildGetFileGroupsByFilterRequest_groupWithNoAccountOnly()246 public void buildGetFileGroupsByFilterRequest_groupWithNoAccountOnly() { 247 Account account = AccountUtil.create("account-name", "account-type"); 248 GetFileGroupsByFilterRequest.Builder builder = 249 GetFileGroupsByFilterRequest.newBuilder() 250 .setGroupWithNoAccountOnly(true) 251 .setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1)) 252 .setAccountOptional(Optional.of(account)); 253 254 // Make sure that when request account independent groups, accountOptional should be absent. 255 assertThrows(IllegalArgumentException.class, builder::build); 256 } 257 258 @Test addFileGroup()259 public void addFileGroup() throws Exception { 260 when(mockMobileDataDownloadManager.addGroupForDownloadInternal( 261 any(GroupKey.class), any(DataFileGroupInternal.class), any())) 262 .thenReturn(Futures.immediateFuture(true)); 263 264 MobileDataDownload mobileDataDownload = 265 new MobileDataDownloadImpl( 266 context, 267 mockEventLogger, 268 mockMobileDataDownloadManager, 269 controlExecutor, 270 ImmutableList.of() /* fileGroupPopulatorList */, 271 Optional.of(mockTaskScheduler), 272 fileStorage, 273 Optional.absent() /* downloadMonitorOptional */, 274 Optional.of(this.getClass()), // don't need to use the real foreground download service. 275 flags, 276 singleFileDownloader, 277 Optional.absent() /* customFileGroupValidator */, 278 timeSource); 279 280 assertThat( 281 mobileDataDownload 282 .addFileGroup( 283 AddFileGroupRequest.newBuilder().setDataFileGroup(FILE_GROUP_1).build()) 284 .get()) 285 .isTrue(); 286 } 287 288 @Test addFileGroup_onFailure()289 public void addFileGroup_onFailure() throws Exception { 290 when(mockMobileDataDownloadManager.addGroupForDownloadInternal( 291 any(GroupKey.class), any(DataFileGroupInternal.class), any())) 292 .thenReturn(Futures.immediateFuture(false)); 293 294 MobileDataDownload mobileDataDownload = 295 new MobileDataDownloadImpl( 296 context, 297 mockEventLogger, 298 mockMobileDataDownloadManager, 299 controlExecutor, 300 ImmutableList.of() /* fileGroupPopulatorList */, 301 Optional.of(mockTaskScheduler), 302 fileStorage, 303 Optional.absent() /* downloadMonitorOptional */, 304 Optional.of(this.getClass()), // don't need to use the real foreground download service. 305 flags, 306 singleFileDownloader, 307 Optional.absent() /* customFileGroupValidator */, 308 timeSource); 309 310 assertThat( 311 mobileDataDownload 312 .addFileGroup( 313 AddFileGroupRequest.newBuilder().setDataFileGroup(FILE_GROUP_1).build()) 314 .get()) 315 .isFalse(); 316 } 317 318 @Test addFileGroup_invalidOwnerPackageName()319 public void addFileGroup_invalidOwnerPackageName() throws Exception { 320 when(mockMobileDataDownloadManager.addGroupForDownloadInternal( 321 any(GroupKey.class), any(DataFileGroupInternal.class), any())) 322 .thenReturn(Futures.immediateFuture(true)); 323 324 // Owner Package should be same as the app package. 325 DataFileGroup dataFileGroup = 326 createDataFileGroup( 327 FILE_GROUP_NAME_1, 328 "PACKAGE_NAME", 329 1 /* versionNumber */, 330 new String[] {FILE_ID_1}, 331 new int[] {FILE_SIZE_1}, 332 new String[] {FILE_CHECKSUM_1}, 333 new String[] {FILE_URL_1}, 334 DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI); 335 336 MobileDataDownload mobileDataDownload = 337 new MobileDataDownloadImpl( 338 context, 339 mockEventLogger, 340 mockMobileDataDownloadManager, 341 controlExecutor, 342 null /* fileGroupPopulatorList */, 343 Optional.of(mockTaskScheduler), 344 fileStorage, 345 Optional.absent() /* downloadMonitorOptional */, 346 Optional.of(this.getClass()), // don't need to use the real foreground download service. 347 flags, 348 singleFileDownloader, 349 Optional.absent() /* customFileGroupValidator */, 350 timeSource); 351 352 expectErrorLogMessage( 353 "MobileDataDownload: Added group = 'test-group-1' with wrong owner package:" 354 + " 'com.google.android.libraries.mobiledatadownload' v.s. 'PACKAGE_NAME' "); 355 assertThat( 356 mobileDataDownload 357 .addFileGroup( 358 AddFileGroupRequest.newBuilder().setDataFileGroup(dataFileGroup).build()) 359 .get()) 360 .isFalse(); 361 } 362 363 @Test addFileGroupWithFileGroupKey()364 public void addFileGroupWithFileGroupKey() throws Exception { 365 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 366 when(mockMobileDataDownloadManager.addGroupForDownloadInternal( 367 groupKeyCaptor.capture(), any(DataFileGroupInternal.class), any())) 368 .thenReturn(Futures.immediateFuture(true)); 369 370 MobileDataDownload mobileDataDownload = 371 new MobileDataDownloadImpl( 372 context, 373 mockEventLogger, 374 mockMobileDataDownloadManager, 375 controlExecutor, 376 ImmutableList.of() /* fileGroupPopulatorList */, 377 Optional.of(mockTaskScheduler), 378 fileStorage, 379 Optional.absent() /* downloadMonitorOptional */, 380 Optional.of(this.getClass()), // don't need to use the real foreground download service. 381 flags, 382 singleFileDownloader, 383 Optional.absent() /* customFileGroupValidator */, 384 timeSource); 385 386 Account account = AccountUtil.create("account-name", "account-type"); 387 AddFileGroupRequest addFileGroupRequest = 388 AddFileGroupRequest.newBuilder() 389 .setDataFileGroup(FILE_GROUP_1) 390 .setAccountOptional(Optional.of(account)) 391 .build(); 392 393 assertThat(mobileDataDownload.addFileGroup(addFileGroupRequest).get()).isTrue(); 394 395 GroupKey groupKey = 396 GroupKey.newBuilder() 397 .setGroupName(FILE_GROUP_NAME_1) 398 .setOwnerPackage(context.getPackageName()) 399 .setAccount(AccountUtil.serialize(account)) 400 .build(); 401 assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey); 402 verify(mockMobileDataDownloadManager) 403 .addGroupForDownloadInternal( 404 eq(groupKey), eq(ProtoConversionUtil.convert(FILE_GROUP_1)), any()); 405 } 406 407 @Test addFileGroupWithFileGroupKey_onFailure()408 public void addFileGroupWithFileGroupKey_onFailure() throws Exception { 409 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 410 when(mockMobileDataDownloadManager.addGroupForDownloadInternal( 411 groupKeyCaptor.capture(), any(DataFileGroupInternal.class), any())) 412 .thenReturn(Futures.immediateFuture(false)); 413 414 MobileDataDownload mobileDataDownload = 415 new MobileDataDownloadImpl( 416 context, 417 mockEventLogger, 418 mockMobileDataDownloadManager, 419 controlExecutor, 420 ImmutableList.of() /* fileGroupPopulatorList */, 421 Optional.of(mockTaskScheduler), 422 fileStorage, 423 Optional.absent() /* downloadMonitorOptional */, 424 Optional.of(this.getClass()), // don't need to use the real foreground download service. 425 flags, 426 singleFileDownloader, 427 Optional.absent() /* customFileGroupValidator */, 428 timeSource); 429 430 Account account = AccountUtil.create("account-name", "account-type"); 431 AddFileGroupRequest addFileGroupRequest = 432 AddFileGroupRequest.newBuilder() 433 .setDataFileGroup(FILE_GROUP_1) 434 .setAccountOptional(Optional.of(account)) 435 .build(); 436 437 assertThat(mobileDataDownload.addFileGroup(addFileGroupRequest).get()).isFalse(); 438 439 GroupKey groupKey = 440 GroupKey.newBuilder() 441 .setGroupName(FILE_GROUP_NAME_1) 442 .setOwnerPackage(context.getPackageName()) 443 .setAccount(AccountUtil.serialize(account)) 444 .build(); 445 assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey); 446 verify(mockMobileDataDownloadManager) 447 .addGroupForDownloadInternal( 448 eq(groupKey), eq(ProtoConversionUtil.convert(FILE_GROUP_1)), any()); 449 } 450 451 @Test addFileGroupWithFileGroupKey_nullAccount()452 public void addFileGroupWithFileGroupKey_nullAccount() throws Exception { 453 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 454 when(mockMobileDataDownloadManager.addGroupForDownloadInternal( 455 groupKeyCaptor.capture(), any(DataFileGroupInternal.class), any())) 456 .thenReturn(Futures.immediateFuture(true)); 457 458 DataFileGroup dataFileGroup = 459 createDataFileGroup( 460 FILE_GROUP_NAME_1, 461 context.getPackageName(), 462 1 /* versionNumber */, 463 new String[] {FILE_ID_1}, 464 new int[] {FILE_SIZE_1}, 465 new String[] {FILE_CHECKSUM_1}, 466 new String[] {FILE_URL_1}, 467 DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI); 468 469 MobileDataDownload mobileDataDownload = 470 new MobileDataDownloadImpl( 471 context, 472 mockEventLogger, 473 mockMobileDataDownloadManager, 474 controlExecutor, 475 ImmutableList.of() /* fileGroupPopulatorList */, 476 Optional.of(mockTaskScheduler), 477 fileStorage, 478 Optional.absent() /* downloadMonitorOptional */, 479 Optional.of(this.getClass()), // don't need to use the real foreground download service. 480 flags, 481 singleFileDownloader, 482 Optional.absent() /* customFileGroupValidator */, 483 timeSource); 484 485 AddFileGroupRequest addFileGroupRequest = 486 AddFileGroupRequest.newBuilder().setDataFileGroup(dataFileGroup).build(); 487 488 assertThat(mobileDataDownload.addFileGroup(addFileGroupRequest).get()).isTrue(); 489 490 GroupKey groupKey = 491 GroupKey.newBuilder() 492 .setGroupName(FILE_GROUP_NAME_1) 493 .setOwnerPackage(context.getPackageName()) 494 .build(); 495 assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey); 496 verify(mockMobileDataDownloadManager) 497 .addGroupForDownloadInternal( 498 eq(groupKey), eq(ProtoConversionUtil.convert(dataFileGroup)), any()); 499 } 500 501 @Test removeFileGroup_onSuccess_returnsTrue()502 public void removeFileGroup_onSuccess_returnsTrue() throws Exception { 503 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 504 when(mockMobileDataDownloadManager.removeFileGroup(groupKeyCaptor.capture(), eq(false))) 505 .thenReturn(Futures.immediateFuture(null /* Void */)); 506 507 MobileDataDownload mobileDataDownload = 508 new MobileDataDownloadImpl( 509 context, 510 mockEventLogger, 511 mockMobileDataDownloadManager, 512 controlExecutor, 513 ImmutableList.of() /* fileGroupPopulatorList */, 514 Optional.of(mockTaskScheduler), 515 fileStorage, 516 Optional.absent() /* downloadMonitorOptional */, 517 Optional.of(this.getClass()), // don't need to use the real foreground download service. 518 flags, 519 singleFileDownloader, 520 Optional.absent() /* customFileGroupValidator */, 521 timeSource); 522 523 RemoveFileGroupRequest removeFileGroupRequest = 524 RemoveFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build(); 525 526 assertThat(mobileDataDownload.removeFileGroup(removeFileGroupRequest).get()).isTrue(); 527 528 GroupKey groupKey = 529 GroupKey.newBuilder() 530 .setGroupName(FILE_GROUP_NAME_1) 531 .setOwnerPackage(context.getPackageName()) 532 .build(); 533 assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey); 534 } 535 536 @Test removeFileGroup_onFailure_returnsFalse()537 public void removeFileGroup_onFailure_returnsFalse() throws Exception { 538 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 539 doThrow(new IOException()) 540 .when(mockMobileDataDownloadManager) 541 .removeFileGroup(groupKeyCaptor.capture(), /* pendingOnly= */ eq(false)); 542 543 MobileDataDownload mobileDataDownload = 544 new MobileDataDownloadImpl( 545 context, 546 mockEventLogger, 547 mockMobileDataDownloadManager, 548 controlExecutor, 549 ImmutableList.of() /* fileGroupPopulatorList */, 550 Optional.of(mockTaskScheduler), 551 fileStorage, 552 Optional.absent() /* downloadMonitorOptional */, 553 Optional.of(this.getClass()), // don't need to use the real foreground download service. 554 flags, 555 singleFileDownloader, 556 Optional.absent() /* customFileGroupValidator */, 557 timeSource); 558 559 RemoveFileGroupRequest removeFileGroupRequest = 560 RemoveFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build(); 561 562 ExecutionException exception = 563 assertThrows( 564 ExecutionException.class, 565 () -> mobileDataDownload.removeFileGroup(removeFileGroupRequest).get()); 566 assertThat(exception).hasCauseThat().isInstanceOf(IOException.class); 567 568 GroupKey groupKey = 569 GroupKey.newBuilder() 570 .setGroupName(FILE_GROUP_NAME_1) 571 .setOwnerPackage(context.getPackageName()) 572 .build(); 573 assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey); 574 } 575 576 @Test removeFileGroup_withAccount_returnsTrue()577 public void removeFileGroup_withAccount_returnsTrue() throws Exception { 578 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 579 when(mockMobileDataDownloadManager.removeFileGroup( 580 groupKeyCaptor.capture(), /* pendingOnly= */ eq(false))) 581 .thenReturn(Futures.immediateFuture(null /* Void */)); 582 583 MobileDataDownload mobileDataDownload = 584 new MobileDataDownloadImpl( 585 context, 586 mockEventLogger, 587 mockMobileDataDownloadManager, 588 controlExecutor, 589 ImmutableList.of() /* fileGroupPopulatorList */, 590 Optional.of(mockTaskScheduler), 591 fileStorage, 592 Optional.absent() /* downloadMonitorOptional */, 593 Optional.of(this.getClass()), // don't need to use the real foreground download service. 594 flags, 595 singleFileDownloader, 596 Optional.absent() /* customFileGroupValidator */, 597 timeSource); 598 599 Account account = AccountUtil.create("account-name", "account-type"); 600 RemoveFileGroupRequest removeFileGroupRequest = 601 RemoveFileGroupRequest.newBuilder() 602 .setGroupName(FILE_GROUP_NAME_1) 603 .setAccountOptional(Optional.of(account)) 604 .build(); 605 606 assertThat(mobileDataDownload.removeFileGroup(removeFileGroupRequest).get()).isTrue(); 607 608 GroupKey groupKey = 609 GroupKey.newBuilder() 610 .setGroupName(FILE_GROUP_NAME_1) 611 .setOwnerPackage(context.getPackageName()) 612 .setAccount(AccountUtil.serialize(account)) 613 .build(); 614 assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey); 615 } 616 617 @Test removeFileGroup_withVariantId_returnsTrue()618 public void removeFileGroup_withVariantId_returnsTrue() throws Exception { 619 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 620 when(mockMobileDataDownloadManager.removeFileGroup( 621 groupKeyCaptor.capture(), /* pendingOnly= */ eq(false))) 622 .thenReturn(Futures.immediateFuture(null /* Void */)); 623 624 MobileDataDownload mobileDataDownload = 625 new MobileDataDownloadImpl( 626 context, 627 mockEventLogger, 628 mockMobileDataDownloadManager, 629 controlExecutor, 630 ImmutableList.of() /* fileGroupPopulatorList */, 631 Optional.of(mockTaskScheduler), 632 fileStorage, 633 Optional.absent() /* downloadMonitorOptional */, 634 Optional.of(this.getClass()), // don't need to use the real foreground download service. 635 flags, 636 singleFileDownloader, 637 Optional.absent() /* customFileGroupValidator */, 638 timeSource); 639 640 RemoveFileGroupRequest removeFileGroupRequest = 641 RemoveFileGroupRequest.newBuilder() 642 .setGroupName(FILE_GROUP_NAME_1) 643 .setVariantIdOptional(Optional.of("en")) 644 .build(); 645 646 assertThat(mobileDataDownload.removeFileGroup(removeFileGroupRequest).get()).isTrue(); 647 648 GroupKey groupKey = 649 GroupKey.newBuilder() 650 .setGroupName(FILE_GROUP_NAME_1) 651 .setOwnerPackage(context.getPackageName()) 652 .setVariantId("en") 653 .build(); 654 assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey); 655 } 656 657 @Test getFileGroup()658 public void getFileGroup() throws Exception { 659 DataFileGroupInternal dataFileGroup = 660 FILE_GROUP_INTERNAL_1.toBuilder().setBuildId(10).setVariantId("test-variant").build(); 661 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 662 .thenReturn(Futures.immediateFuture(dataFileGroup)); 663 when(mockMobileDataDownloadManager.getDataFileUris( 664 dataFileGroup, /* verifyIsolatedStructure= */ true)) 665 .thenReturn( 666 Futures.immediateFuture(ImmutableMap.of(dataFileGroup.getFile(0), onDeviceUri1))); 667 668 MobileDataDownload mobileDataDownload = 669 new MobileDataDownloadImpl( 670 context, 671 mockEventLogger, 672 mockMobileDataDownloadManager, 673 controlExecutor, 674 ImmutableList.of() /* fileGroupPopulatorList */, 675 Optional.of(mockTaskScheduler), 676 fileStorage, 677 Optional.absent() /* downloadMonitorOptional */, 678 Optional.of(this.getClass()), // don't need to use the real foreground download service. 679 flags, 680 singleFileDownloader, 681 Optional.absent() /* customFileGroupValidator */, 682 timeSource); 683 684 ClientFileGroup clientFileGroup = 685 mobileDataDownload 686 .getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 687 .get(); 688 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 689 assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 690 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 691 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 692 assertThat(clientFileGroup.hasAccount()).isFalse(); 693 694 ClientFile clientFile = clientFileGroup.getFileList().get(0); 695 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 696 assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString()); 697 } 698 699 @Test getFileGroup_withDirectory()700 public void getFileGroup_withDirectory() throws Exception { 701 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 702 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 703 when(mockMobileDataDownloadManager.getDataFileUris( 704 FILE_GROUP_INTERNAL_1, /* verifyIsolatedStructure= */ true)) 705 .thenReturn( 706 Futures.immediateFuture( 707 ImmutableMap.of(FILE_GROUP_INTERNAL_1.getFile(0), onDeviceDirUri))); 708 709 MobileDataDownload mobileDataDownload = 710 new MobileDataDownloadImpl( 711 context, 712 mockEventLogger, 713 mockMobileDataDownloadManager, 714 controlExecutor, 715 ImmutableList.of() /* fileGroupPopulatorList */, 716 Optional.of(mockTaskScheduler), 717 fileStorage, 718 Optional.absent() /* downloadMonitorOptional */, 719 Optional.of(this.getClass()), // don't need to use the real foreground download service. 720 flags, 721 singleFileDownloader, 722 Optional.absent() /* customFileGroupValidator */, 723 timeSource); 724 725 ClientFileGroup clientFileGroup = 726 mobileDataDownload 727 .getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 728 .get(); 729 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 730 assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 731 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 732 assertThat(clientFileGroup.getFileCount()).isEqualTo(3); 733 assertThat(clientFileGroup.hasAccount()).isFalse(); 734 735 List<ClientFile> clientFileList = clientFileGroup.getFileList(); 736 assertThat(clientFileList) 737 .contains( 738 ClientFile.newBuilder() 739 .setFileId("/file_1") 740 .setFileUri(onDeviceDirFileUri1.toString()) 741 .setFullSizeInBytes(onDeviceDirFile1Content.getBytes(UTF_8).length) 742 .build()); 743 assertThat(clientFileList) 744 .contains( 745 ClientFile.newBuilder() 746 .setFileId("/file_2") 747 .setFileUri(onDeviceDirFileUri2.toString()) 748 .setFullSizeInBytes(onDeviceDirFile2Content.getBytes(UTF_8).length) 749 .build()); 750 assertThat(clientFileList) 751 .contains( 752 ClientFile.newBuilder() 753 .setFileId("/sub/file") 754 .setFileUri(onDeviceDirFileUri3.toString()) 755 .setFullSizeInBytes(onDeviceDirFile3Content.getBytes(UTF_8).length) 756 .build()); 757 } 758 759 @Test getFileGroup_withDirectory_withTraverseDisabled()760 public void getFileGroup_withDirectory_withTraverseDisabled() throws Exception { 761 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 762 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 763 when(mockMobileDataDownloadManager.getDataFileUris( 764 FILE_GROUP_INTERNAL_1, /* verifyIsolatedStructure= */ true)) 765 .thenReturn( 766 Futures.immediateFuture( 767 ImmutableMap.of(FILE_GROUP_INTERNAL_1.getFile(0), onDeviceDirUri))); 768 769 MobileDataDownload mobileDataDownload = 770 new MobileDataDownloadImpl( 771 context, 772 mockEventLogger, 773 mockMobileDataDownloadManager, 774 controlExecutor, 775 ImmutableList.of() /* fileGroupPopulatorList */, 776 Optional.of(mockTaskScheduler), 777 fileStorage, 778 Optional.absent() /* downloadMonitorOptional */, 779 Optional.of(this.getClass()), // don't need to use the real foreground download service. 780 flags, 781 singleFileDownloader, 782 Optional.absent() /* customFileGroupValidator */, 783 timeSource); 784 785 ClientFileGroup clientFileGroup = 786 mobileDataDownload 787 .getFileGroup( 788 GetFileGroupRequest.newBuilder() 789 .setPreserveZipDirectories(true) 790 .setGroupName(FILE_GROUP_NAME_1) 791 .build()) 792 .get(); 793 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 794 assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 795 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 796 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 797 assertThat(clientFileGroup.hasAccount()).isFalse(); 798 799 List<ClientFile> clientFileList = clientFileGroup.getFileList(); 800 assertThat(clientFileList) 801 .contains( 802 ClientFile.newBuilder() 803 .setFileId("test-file-1") 804 .setFileUri(onDeviceDirUri.toString()) 805 .setFullSizeInBytes(FILE_SIZE_1) 806 .build()); 807 assertThat(fileStorage.isDirectory(Uri.parse(clientFileList.get(0).getFileUri()))).isTrue(); 808 } 809 810 @Test removeFileGroupsByFilter_withAccountSpecified_removesMatchingAccountGroups()811 public void removeFileGroupsByFilter_withAccountSpecified_removesMatchingAccountGroups() 812 throws Exception { 813 List<GroupKeyAndGroup> keyToGroupList = new ArrayList<>(); 814 Account account1 = AccountUtil.create("account-name", "account-type"); 815 Account account2 = AccountUtil.create("account-name2", "account-type"); 816 817 DataFileGroupInternal downloadedFileGroup = FILE_GROUP_INTERNAL_1.toBuilder().build(); 818 DataFileGroupInternal pendingFileGroup = 819 FILE_GROUP_INTERNAL_1.toBuilder().setFileGroupVersionNumber(6).build(); 820 821 GroupKey account1GroupKey = 822 GroupKey.newBuilder() 823 .setGroupName(FILE_GROUP_NAME_1) 824 .setOwnerPackage(context.getPackageName()) 825 .setAccount(AccountUtil.serialize(account1)) 826 .build(); 827 GroupKey downloadedAccount1GroupKey = account1GroupKey.toBuilder().setDownloaded(true).build(); 828 GroupKey pendingAccount1GroupKey = account1GroupKey.toBuilder().setDownloaded(false).build(); 829 830 GroupKey account2GroupKey = 831 GroupKey.newBuilder() 832 .setGroupName(FILE_GROUP_NAME_1) 833 .setOwnerPackage(context.getPackageName()) 834 .setAccount(AccountUtil.serialize(account2)) 835 .build(); 836 GroupKey downloadedAccount2GroupKey = account2GroupKey.toBuilder().setDownloaded(true).build(); 837 GroupKey pendingAccount2GroupKey = account2GroupKey.toBuilder().setDownloaded(false).build(); 838 839 GroupKey noAccountGroupKey = 840 GroupKey.newBuilder() 841 .setGroupName(FILE_GROUP_NAME_1) 842 .setOwnerPackage(context.getPackageName()) 843 .build(); 844 GroupKey downloadedGroupKey = noAccountGroupKey.toBuilder().setDownloaded(true).build(); 845 GroupKey pendingGroupKey = noAccountGroupKey.toBuilder().setDownloaded(false).build(); 846 847 keyToGroupList.add(GroupKeyAndGroup.create(downloadedGroupKey, downloadedFileGroup)); 848 keyToGroupList.add(GroupKeyAndGroup.create(downloadedAccount1GroupKey, downloadedFileGroup)); 849 keyToGroupList.add(GroupKeyAndGroup.create(downloadedAccount2GroupKey, downloadedFileGroup)); 850 keyToGroupList.add(GroupKeyAndGroup.create(pendingGroupKey, pendingFileGroup)); 851 keyToGroupList.add(GroupKeyAndGroup.create(pendingAccount1GroupKey, pendingFileGroup)); 852 keyToGroupList.add(GroupKeyAndGroup.create(pendingAccount2GroupKey, pendingFileGroup)); 853 854 when(mockMobileDataDownloadManager.getAllFreshGroups()) 855 .thenReturn(Futures.immediateFuture(keyToGroupList)); 856 when(mockMobileDataDownloadManager.removeFileGroups(groupKeysCaptor.capture())) 857 .thenReturn(Futures.immediateVoidFuture()); 858 859 MobileDataDownload mobileDataDownload = 860 new MobileDataDownloadImpl( 861 context, 862 mockEventLogger, 863 mockMobileDataDownloadManager, 864 controlExecutor, 865 /* fileGroupPopulatorList= */ ImmutableList.of(), 866 Optional.of(mockTaskScheduler), 867 fileStorage, 868 /* downloadMonitorOptional= */ Optional.absent(), 869 /* foregroundDownloadServiceClassOptional= */ Optional.absent(), 870 flags, 871 singleFileDownloader, 872 Optional.absent() /* customFileGroupValidator */, 873 timeSource); 874 875 // Setup request that matches all fresh groups, but also include account to make sure only 876 // account associated file groups are removed 877 RemoveFileGroupsByFilterRequest removeFileGroupsByFilterRequest = 878 RemoveFileGroupsByFilterRequest.newBuilder() 879 .setAccountOptional(Optional.of(account1)) 880 .build(); 881 882 RemoveFileGroupsByFilterResponse response = 883 mobileDataDownload.removeFileGroupsByFilter(removeFileGroupsByFilterRequest).get(); 884 885 assertThat(response.removedFileGroupsCount()).isEqualTo(1); 886 verify(mockMobileDataDownloadManager, times(1)).removeFileGroups(anyList()); 887 List<GroupKey> removedGroupKeys = groupKeysCaptor.getValue(); 888 assertThat(removedGroupKeys).containsExactly(account1GroupKey); 889 } 890 891 @Test getFileGroup_nullFileUri()892 public void getFileGroup_nullFileUri() throws Exception { 893 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 894 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 895 when(mockMobileDataDownloadManager.getDataFileUris( 896 FILE_GROUP_INTERNAL_1, /* verifyIsolatedStructure= */ true)) 897 .thenReturn( 898 Futures.immediateFailedFuture( 899 DownloadException.builder() 900 .setDownloadResultCode(DownloadResultCode.UNKNOWN_ERROR) 901 .setMessage("Fail to download file group") 902 .build())); 903 904 MobileDataDownload mobileDataDownload = 905 new MobileDataDownloadImpl( 906 context, 907 mockEventLogger, 908 mockMobileDataDownloadManager, 909 controlExecutor, 910 ImmutableList.of() /* fileGroupPopulatorList */, 911 Optional.of(mockTaskScheduler), 912 fileStorage, 913 Optional.absent() /* downloadMonitorOptional */, 914 Optional.of(this.getClass()), // don't need to use the real foreground download service. 915 flags, 916 singleFileDownloader, 917 Optional.absent() /* customFileGroupValidator */, 918 timeSource); 919 920 assertNull( 921 mobileDataDownload 922 .getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 923 .get()); 924 } 925 926 @Test getFileGroup_null()927 public void getFileGroup_null() throws Exception { 928 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 929 .thenReturn(Futures.immediateFuture(null)); 930 931 MobileDataDownload mobileDataDownload = 932 new MobileDataDownloadImpl( 933 context, 934 mockEventLogger, 935 mockMobileDataDownloadManager, 936 controlExecutor, 937 ImmutableList.of() /* fileGroupPopulatorList */, 938 Optional.of(mockTaskScheduler), 939 fileStorage, 940 Optional.absent() /* downloadMonitorOptional */, 941 Optional.of(this.getClass()), // don't need to use the real foreground download service. 942 flags, 943 singleFileDownloader, 944 Optional.absent() /* customFileGroupValidator */, 945 timeSource); 946 947 assertNull( 948 mobileDataDownload 949 .getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 950 .get()); 951 } 952 953 @Test getFileGroup_withAccount()954 public void getFileGroup_withAccount() throws Exception { 955 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 956 when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(true))) 957 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 958 when(mockMobileDataDownloadManager.getDataFileUris( 959 FILE_GROUP_INTERNAL_1, /* verifyIsolatedStructure= */ true)) 960 .thenReturn( 961 Futures.immediateFuture( 962 ImmutableMap.of(FILE_GROUP_INTERNAL_1.getFile(0), onDeviceUri1))); 963 964 MobileDataDownload mobileDataDownload = 965 new MobileDataDownloadImpl( 966 context, 967 mockEventLogger, 968 mockMobileDataDownloadManager, 969 controlExecutor, 970 ImmutableList.of() /* fileGroupPopulatorList */, 971 Optional.of(mockTaskScheduler), 972 fileStorage, 973 Optional.absent() /* downloadMonitorOptional */, 974 Optional.of(this.getClass()), // don't need to use the real foreground download service. 975 flags, 976 singleFileDownloader, 977 Optional.absent() /* customFileGroupValidator */, 978 timeSource); 979 980 Account account = AccountUtil.create("account-name", "account-type"); 981 ClientFileGroup clientFileGroup = 982 mobileDataDownload 983 .getFileGroup( 984 GetFileGroupRequest.newBuilder() 985 .setGroupName(FILE_GROUP_NAME_1) 986 .setAccountOptional(Optional.of(account)) 987 .build()) 988 .get(); 989 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 990 assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 991 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 992 assertThat(clientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account)); 993 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 994 995 ClientFile clientFile = clientFileGroup.getFileList().get(0); 996 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 997 assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString()); 998 999 GroupKey groupKey = 1000 GroupKey.newBuilder() 1001 .setGroupName(FILE_GROUP_NAME_1) 1002 .setOwnerPackage(context.getPackageName()) 1003 .setAccount(AccountUtil.serialize(account)) 1004 .build(); 1005 assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey); 1006 } 1007 1008 @Test getFileGroup_withVariantId()1009 public void getFileGroup_withVariantId() throws Exception { 1010 DataFileGroupInternal dataFileGroup = 1011 FILE_GROUP_INTERNAL_1.toBuilder().setVariantId("en").build(); 1012 1013 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 1014 when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(true))) 1015 .thenReturn(Futures.immediateFuture(dataFileGroup)); 1016 when(mockMobileDataDownloadManager.getDataFileUris( 1017 dataFileGroup, /* verifyIsolatedStructure= */ true)) 1018 .thenReturn( 1019 Futures.immediateFuture(ImmutableMap.of(dataFileGroup.getFile(0), onDeviceUri1))); 1020 1021 MobileDataDownload mobileDataDownload = 1022 new MobileDataDownloadImpl( 1023 context, 1024 mockEventLogger, 1025 mockMobileDataDownloadManager, 1026 controlExecutor, 1027 ImmutableList.of() /* fileGroupPopulatorList */, 1028 Optional.of(mockTaskScheduler), 1029 fileStorage, 1030 Optional.absent() /* downloadMonitorOptional */, 1031 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1032 flags, 1033 singleFileDownloader, 1034 Optional.absent() /* customFileGroupValidator */, 1035 timeSource); 1036 1037 ClientFileGroup clientFileGroup = 1038 mobileDataDownload 1039 .getFileGroup( 1040 GetFileGroupRequest.newBuilder() 1041 .setGroupName(FILE_GROUP_NAME_1) 1042 .setVariantIdOptional(Optional.of("en")) 1043 .build()) 1044 .get(); 1045 1046 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1047 assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 1048 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 1049 assertThat(clientFileGroup.getAccount()).isEmpty(); 1050 assertThat(clientFileGroup.getVariantId()).isEqualTo("en"); 1051 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 1052 1053 GroupKey groupKey = 1054 GroupKey.newBuilder() 1055 .setGroupName(FILE_GROUP_NAME_1) 1056 .setOwnerPackage(context.getPackageName()) 1057 .setVariantId("en") 1058 .build(); 1059 assertThat(groupKeyCaptor.getValue()).isEqualTo(groupKey); 1060 } 1061 1062 @Test getFileGroup_includesIdentifyingProperties()1063 public void getFileGroup_includesIdentifyingProperties() throws Exception { 1064 Any customProperty = 1065 Any.newBuilder() 1066 .setTypeUrl("type.googleapis.com/google.protobuf.stringvalue") 1067 .setValue(StringValue.of("TEST_PROPERTY").toByteString()) 1068 .build(); 1069 DataFileGroupInternal dataFileGroup = 1070 FILE_GROUP_INTERNAL_1.toBuilder() 1071 .setBuildId(1L) 1072 .setVariantId("testvariant") 1073 .setCustomProperty(customProperty) 1074 .build(); 1075 1076 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 1077 .thenReturn(Futures.immediateFuture(dataFileGroup)); 1078 when(mockMobileDataDownloadManager.getDataFileUris( 1079 dataFileGroup, /* verifyIsolatedStructure= */ true)) 1080 .thenReturn( 1081 Futures.immediateFuture(ImmutableMap.of(dataFileGroup.getFile(0), onDeviceUri1))); 1082 1083 MobileDataDownload mobileDataDownload = 1084 new MobileDataDownloadImpl( 1085 context, 1086 mockEventLogger, 1087 mockMobileDataDownloadManager, 1088 controlExecutor, 1089 ImmutableList.of() /* fileGroupPopulatorList */, 1090 Optional.of(mockTaskScheduler), 1091 fileStorage, 1092 Optional.absent() /* downloadMonitorOptional */, 1093 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1094 flags, 1095 singleFileDownloader, 1096 Optional.absent() /* customFileGroupValidator */, 1097 timeSource); 1098 1099 ClientFileGroup clientFileGroup = 1100 mobileDataDownload 1101 .getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 1102 .get(); 1103 1104 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1105 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 1106 assertThat(clientFileGroup.getBuildId()).isEqualTo(1L); 1107 assertThat(clientFileGroup.getVariantId()).isEqualTo("testvariant"); 1108 assertThat(clientFileGroup.getCustomProperty()).isEqualTo(customProperty); 1109 } 1110 1111 @Test getFileGroup_includesLocale()1112 public void getFileGroup_includesLocale() throws Exception { 1113 DataFileGroupInternal dataFileGroup = 1114 FILE_GROUP_INTERNAL_1.toBuilder().addLocale("en-US").addLocale("en-CA").build(); 1115 1116 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 1117 .thenReturn(Futures.immediateFuture(dataFileGroup)); 1118 when(mockMobileDataDownloadManager.getDataFileUris( 1119 dataFileGroup, /* verifyIsolatedStructure= */ true)) 1120 .thenReturn( 1121 Futures.immediateFuture(ImmutableMap.of(dataFileGroup.getFile(0), onDeviceUri1))); 1122 1123 MobileDataDownload mobileDataDownload = 1124 new MobileDataDownloadImpl( 1125 context, 1126 mockEventLogger, 1127 mockMobileDataDownloadManager, 1128 controlExecutor, 1129 ImmutableList.of() /* fileGroupPopulatorList */, 1130 Optional.of(mockTaskScheduler), 1131 fileStorage, 1132 Optional.absent() /* downloadMonitorOptional */, 1133 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1134 flags, 1135 singleFileDownloader, 1136 Optional.absent() /* customFileGroupValidator */, 1137 timeSource); 1138 1139 ClientFileGroup clientFileGroup = 1140 mobileDataDownload 1141 .getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 1142 .get(); 1143 1144 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1145 assertThat(clientFileGroup.getLocaleList()).containsExactly("en-US", "en-CA"); 1146 } 1147 1148 @Test getFileGroup_includesGroupLevelMetadataWhenProvided()1149 public void getFileGroup_includesGroupLevelMetadataWhenProvided() throws Exception { 1150 Any customMetadata = 1151 Any.newBuilder() 1152 .setTypeUrl("type.googleapis.com/google.protobuf.stringvalue") 1153 .setValue(StringValue.of("TEST_METADATA").toByteString()) 1154 .build(); 1155 DataFileGroupInternal dataFileGroup = 1156 FILE_GROUP_INTERNAL_1.toBuilder().setCustomMetadata(customMetadata).build(); 1157 1158 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 1159 .thenReturn(Futures.immediateFuture(dataFileGroup)); 1160 when(mockMobileDataDownloadManager.getDataFileUris( 1161 dataFileGroup, /* verifyIsolatedStructure= */ true)) 1162 .thenReturn( 1163 Futures.immediateFuture(ImmutableMap.of(dataFileGroup.getFile(0), onDeviceUri1))); 1164 1165 MobileDataDownload mobileDataDownload = 1166 new MobileDataDownloadImpl( 1167 context, 1168 mockEventLogger, 1169 mockMobileDataDownloadManager, 1170 controlExecutor, 1171 ImmutableList.of() /* fileGroupPopulatorList */, 1172 Optional.of(mockTaskScheduler), 1173 fileStorage, 1174 Optional.absent() /* downloadMonitorOptional */, 1175 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1176 flags, 1177 singleFileDownloader, 1178 Optional.absent() /* customFileGroupValidator */, 1179 timeSource); 1180 1181 ClientFileGroup clientFileGroup = 1182 mobileDataDownload 1183 .getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 1184 .get(); 1185 1186 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1187 assertThat(clientFileGroup.getCustomMetadata()).isEqualTo(customMetadata); 1188 } 1189 1190 @Test getFileGroup_includesFileLevelMetadataWhenProvided()1191 public void getFileGroup_includesFileLevelMetadataWhenProvided() throws Exception { 1192 Any customMetadata = 1193 Any.newBuilder() 1194 .setTypeUrl("type.googleapis.com/google.protobuf.stringvalue") 1195 .setValue(StringValue.of("TEST_METADATA").toByteString()) 1196 .build(); 1197 DataFileGroupInternal dataFileGroup = 1198 DataFileGroupInternal.newBuilder() 1199 .setGroupName(FILE_GROUP_NAME_1) 1200 .setOwnerPackage(context.getPackageName()) 1201 .addFile( 1202 MetadataProto.DataFile.newBuilder() 1203 .setFileId(FILE_ID_1) 1204 .setUrlToDownload(FILE_URL_1) 1205 .setCustomMetadata(customMetadata) 1206 .build()) 1207 .addFile( 1208 MetadataProto.DataFile.newBuilder() 1209 .setFileId(FILE_ID_2) 1210 .setUrlToDownload(FILE_URL_2) 1211 .build()) 1212 .build(); 1213 1214 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 1215 .thenReturn(Futures.immediateFuture(dataFileGroup)); 1216 when(mockMobileDataDownloadManager.getDataFileUris( 1217 dataFileGroup, /* verifyIsolatedStructure= */ true)) 1218 .thenReturn( 1219 Futures.immediateFuture( 1220 ImmutableMap.of( 1221 dataFileGroup.getFile(0), 1222 onDeviceUri1, 1223 dataFileGroup.getFile(1), 1224 onDeviceUri1))); 1225 1226 MobileDataDownload mobileDataDownload = 1227 new MobileDataDownloadImpl( 1228 context, 1229 mockEventLogger, 1230 mockMobileDataDownloadManager, 1231 controlExecutor, 1232 ImmutableList.of() /* fileGroupPopulatorList */, 1233 Optional.of(mockTaskScheduler), 1234 fileStorage, 1235 Optional.absent() /* downloadMonitorOptional */, 1236 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1237 flags, 1238 singleFileDownloader, 1239 Optional.absent() /* customFileGroupValidator */, 1240 timeSource); 1241 1242 ClientFileGroup clientFileGroup = 1243 mobileDataDownload 1244 .getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 1245 .get(); 1246 1247 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1248 assertThat(clientFileGroup.hasCustomMetadata()).isFalse(); 1249 1250 ClientFile clientFile1 = 1251 clientFileGroup.getFile(0).getFileId().equals(FILE_ID_1) 1252 ? clientFileGroup.getFile(0) 1253 : clientFileGroup.getFile(1); 1254 ClientFile clientFile2 = 1255 clientFileGroup.getFile(0).getFileId().equals(FILE_ID_1) 1256 ? clientFileGroup.getFile(1) 1257 : clientFileGroup.getFile(0); 1258 1259 assertThat(clientFile1.hasCustomMetadata()).isTrue(); 1260 assertThat(clientFile1.getCustomMetadata()).isEqualTo(customMetadata); 1261 assertThat(clientFile2.hasCustomMetadata()).isFalse(); 1262 } 1263 1264 @Test getFileGroup_whenVerifyIsolatedStructureIsFalse_skipsStructureVerification()1265 public void getFileGroup_whenVerifyIsolatedStructureIsFalse_skipsStructureVerification() 1266 throws Exception { 1267 MetadataProto.DataFile isolatedStructureFile = 1268 MetadataProto.DataFile.newBuilder() 1269 .setFileId(FILE_ID_1) 1270 .setChecksumType(MetadataProto.DataFile.ChecksumType.NONE) 1271 .setUrlToDownload(FILE_URL_1) 1272 .setRelativeFilePath("mycustom/file.txt") 1273 .build(); 1274 DataFileGroupInternal isolatedStructureGroup = 1275 DataFileGroupInternal.newBuilder() 1276 .setGroupName(FILE_GROUP_NAME_1) 1277 .setOwnerPackage(context.getPackageName()) 1278 .setPreserveFilenamesAndIsolateFiles(true) 1279 .addFile(isolatedStructureFile) 1280 .build(); 1281 1282 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 1283 .thenReturn(Futures.immediateFuture(isolatedStructureGroup)); 1284 when(mockMobileDataDownloadManager.getDataFileUris( 1285 isolatedStructureGroup, /* verifyIsolatedStructure= */ false)) 1286 .thenReturn( 1287 Futures.immediateFuture( 1288 ImmutableMap.of(isolatedStructureGroup.getFile(0), onDeviceUri1))); 1289 1290 MobileDataDownload mobileDataDownload = 1291 new MobileDataDownloadImpl( 1292 context, 1293 mockEventLogger, 1294 mockMobileDataDownloadManager, 1295 controlExecutor, 1296 ImmutableList.of() /* fileGroupPopulatorList */, 1297 Optional.of(mockTaskScheduler), 1298 fileStorage, 1299 Optional.absent() /* downloadMonitorOptional */, 1300 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1301 flags, 1302 singleFileDownloader, 1303 Optional.absent() /* customFileGroupValidator */, 1304 timeSource); 1305 1306 ClientFileGroup clientFileGroup = 1307 mobileDataDownload 1308 .getFileGroup( 1309 GetFileGroupRequest.newBuilder() 1310 .setGroupName(FILE_GROUP_NAME_1) 1311 .setVerifyIsolatedStructure(false) 1312 .build()) 1313 .get(); 1314 1315 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1316 assertThat(clientFileGroup.getFile(0).getFileUri()).isEqualTo(onDeviceUri1.toString()); 1317 1318 // Verify getting the file uri bypassed the verify check. 1319 verify(mockMobileDataDownloadManager, never()).getDataFileUris(any(), eq(true)); 1320 } 1321 1322 @Test getFileGroup_whenVerifyIsolatedStructureIsTrue_returnsNullOnInvalidStructure()1323 public void getFileGroup_whenVerifyIsolatedStructureIsTrue_returnsNullOnInvalidStructure() 1324 throws Exception { 1325 MetadataProto.DataFile isolatedStructureFile = 1326 MetadataProto.DataFile.newBuilder() 1327 .setFileId(FILE_ID_1) 1328 .setChecksumType(MetadataProto.DataFile.ChecksumType.NONE) 1329 .setUrlToDownload(FILE_URL_1) 1330 .setRelativeFilePath("mycustom/file.txt") 1331 .build(); 1332 DataFileGroupInternal isolatedStructureGroup = 1333 DataFileGroupInternal.newBuilder() 1334 .setGroupName(FILE_GROUP_NAME_1) 1335 .setOwnerPackage(context.getPackageName()) 1336 .setPreserveFilenamesAndIsolateFiles(true) 1337 .addFile(isolatedStructureFile) 1338 .build(); 1339 1340 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 1341 .thenReturn(Futures.immediateFuture(isolatedStructureGroup)); 1342 1343 // Mock that verification failed 1344 when(mockMobileDataDownloadManager.getDataFileUris( 1345 isolatedStructureGroup, /* verifyIsolatedStructure= */ true)) 1346 .thenReturn(Futures.immediateFuture(ImmutableMap.of())); 1347 1348 MobileDataDownload mobileDataDownload = 1349 new MobileDataDownloadImpl( 1350 context, 1351 mockEventLogger, 1352 mockMobileDataDownloadManager, 1353 controlExecutor, 1354 ImmutableList.of() /* fileGroupPopulatorList */, 1355 Optional.of(mockTaskScheduler), 1356 fileStorage, 1357 Optional.absent() /* downloadMonitorOptional */, 1358 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1359 flags, 1360 singleFileDownloader, 1361 Optional.absent() /* customFileGroupValidator */, 1362 timeSource); 1363 1364 // Assert that a failure to verify the isolated structure returns a null group 1365 assertThat( 1366 mobileDataDownload 1367 .getFileGroup( 1368 GetFileGroupRequest.newBuilder() 1369 .setGroupName(FILE_GROUP_NAME_1) 1370 .setVerifyIsolatedStructure(true) 1371 .build()) 1372 .get()) 1373 .isNull(); 1374 1375 // Verify getting the file uri did not bypass the verify check. 1376 verify(mockMobileDataDownloadManager, never()).getDataFileUris(any(), eq(false)); 1377 } 1378 1379 @Test getFileGroup_fileGroupFound_logsQueryStatsForFileGroup()1380 public void getFileGroup_fileGroupFound_logsQueryStatsForFileGroup() throws Exception { 1381 DataFileGroupInternal dataFileGroup = 1382 FILE_GROUP_INTERNAL_1.toBuilder().setBuildId(10).setVariantId("test-variant").build(); 1383 when(mockMobileDataDownloadManager.getFileGroup( 1384 any(GroupKey.class), /* downloaded= */ eq(true))) 1385 .thenReturn(Futures.immediateFuture(dataFileGroup)); 1386 when(mockMobileDataDownloadManager.getDataFileUris( 1387 dataFileGroup, /* verifyIsolatedStructure= */ true)) 1388 .thenReturn( 1389 Futures.immediateFuture(ImmutableMap.of(dataFileGroup.getFile(0), onDeviceUri1))); 1390 1391 MobileDataDownload mobileDataDownload = 1392 new MobileDataDownloadImpl( 1393 context, 1394 fakeEventLogger, 1395 mockMobileDataDownloadManager, 1396 controlExecutor, 1397 /* fileGroupPopulatorList= */ ImmutableList.of(), 1398 Optional.of(mockTaskScheduler), 1399 fileStorage, 1400 /* downloadMonitorOptional= */ Optional.absent(), 1401 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1402 flags, 1403 singleFileDownloader, 1404 /* customValidatorOptional= */ Optional.absent(), 1405 timeSource); 1406 1407 ClientFileGroup unused = 1408 mobileDataDownload 1409 .getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 1410 .get(); 1411 1412 List<DataDownloadFileGroupStats> fileGroupDetailsList = 1413 fakeEventLogger.getLoggedMddQueryStats(); 1414 1415 assertThat(fileGroupDetailsList).hasSize(1); 1416 DataDownloadFileGroupStats fileGroupStats = fileGroupDetailsList.get(0); 1417 assertThat(fileGroupStats.getFileGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1418 assertThat(fileGroupStats.getOwnerPackage()).isEqualTo(context.getPackageName()); 1419 assertThat(fileGroupStats.getFileGroupVersionNumber()).isEqualTo(5); 1420 assertThat(fileGroupStats.getBuildId()).isEqualTo(10); 1421 assertThat(fileGroupStats.getVariantId()).isEqualTo("test-variant"); 1422 assertThat(fileGroupStats.getFileCount()).isEqualTo(1); 1423 } 1424 1425 @Test getFileGroup_fileGroupFound_doesNotOverLog()1426 public void getFileGroup_fileGroupFound_doesNotOverLog() throws Exception { 1427 DataFileGroupInternal dataFileGroup = FILE_GROUP_INTERNAL_1; 1428 when(mockMobileDataDownloadManager.getFileGroup( 1429 any(GroupKey.class), /* downloaded= */ eq(true))) 1430 .thenReturn(Futures.immediateFuture(dataFileGroup)); 1431 when(mockMobileDataDownloadManager.getDataFileUris( 1432 dataFileGroup, /* verifyIsolatedStructure= */ true)) 1433 .thenReturn( 1434 Futures.immediateFuture(ImmutableMap.of(dataFileGroup.getFile(0), onDeviceUri1))); 1435 1436 MobileDataDownload mobileDataDownload = 1437 new MobileDataDownloadImpl( 1438 context, 1439 mockEventLogger, 1440 mockMobileDataDownloadManager, 1441 controlExecutor, 1442 /* fileGroupPopulatorList= */ ImmutableList.of(), 1443 Optional.of(mockTaskScheduler), 1444 fileStorage, 1445 /* downloadMonitorOptional= */ Optional.absent(), 1446 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1447 flags, 1448 singleFileDownloader, 1449 /* customValidatorOptional= */ Optional.absent(), 1450 timeSource); 1451 1452 ClientFileGroup unused = 1453 mobileDataDownload 1454 .getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 1455 .get(); 1456 1457 verify(mockEventLogger).logMddQueryStats(any()); 1458 verify(mockEventLogger).logMddLibApiResultLog(any()); 1459 verifyNoMoreInteractions(mockEventLogger); 1460 } 1461 1462 @Test getFileGroup_fileGroupNotFound_doesNotOverLog()1463 public void getFileGroup_fileGroupNotFound_doesNotOverLog() throws Exception { 1464 when(mockMobileDataDownloadManager.getFileGroup( 1465 any(GroupKey.class), /* downloaded= */ eq(true))) 1466 .thenReturn(Futures.immediateFuture(null)); 1467 1468 MobileDataDownload mobileDataDownload = 1469 new MobileDataDownloadImpl( 1470 context, 1471 mockEventLogger, 1472 mockMobileDataDownloadManager, 1473 controlExecutor, 1474 /* fileGroupPopulatorList= */ ImmutableList.of(), 1475 Optional.of(mockTaskScheduler), 1476 fileStorage, 1477 /* downloadMonitorOptional= */ Optional.absent(), 1478 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1479 flags, 1480 singleFileDownloader, 1481 /* customValidatorOptional= */ Optional.absent(), 1482 timeSource); 1483 1484 ClientFileGroup unused = 1485 mobileDataDownload 1486 .getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 1487 .get(); 1488 1489 verify(mockEventLogger).logMddLibApiResultLog(any()); 1490 verifyNoMoreInteractions(mockEventLogger); 1491 } 1492 1493 @Test getFileGroup_throwsException_doesNotOverLog()1494 public void getFileGroup_throwsException_doesNotOverLog() throws Exception { 1495 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 1496 .thenReturn(Futures.immediateFailedFuture(new Exception())); 1497 1498 MobileDataDownload mobileDataDownload = 1499 new MobileDataDownloadImpl( 1500 context, 1501 mockEventLogger, 1502 mockMobileDataDownloadManager, 1503 controlExecutor, 1504 /* fileGroupPopulatorList= */ ImmutableList.of(), 1505 Optional.of(mockTaskScheduler), 1506 fileStorage, 1507 /* downloadMonitorOptional= */ Optional.absent(), 1508 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1509 flags, 1510 singleFileDownloader, 1511 /* customValidatorOptional= */ Optional.absent(), 1512 timeSource); 1513 1514 assertThrows( 1515 ExecutionException.class, 1516 () -> 1517 mobileDataDownload 1518 .getFileGroup( 1519 GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 1520 .get()); 1521 1522 verify(mockEventLogger).logMddLibApiResultLog(any()); 1523 verifyNoMoreInteractions(mockEventLogger); 1524 } 1525 1526 /** 1527 * Helper function to test that expected errors are being logged. 1528 * 1529 * <p>causeThrowable is used to check for cause only if expectedThrowable is instance of 1530 * ExecutionException. 1531 */ getFileGroupErrorLoggingTestHelper( ListenableFuture<?> getFileGroupResultFuture, Class<T> expectedThrowable, Class<?> causeThrowable, int code)1532 private <T extends Throwable> void getFileGroupErrorLoggingTestHelper( 1533 ListenableFuture<?> getFileGroupResultFuture, 1534 Class<T> expectedThrowable, 1535 Class<?> causeThrowable, 1536 int code) 1537 throws Exception { 1538 long latencyNs = 1000; 1539 when(mockMobileDataDownloadManager.getFileGroup( 1540 any(GroupKey.class), /* downloaded= */ eq(true))) 1541 .thenAnswer( 1542 invocation -> { 1543 // Advancing time source to test latency. 1544 timeSource.advance(latencyNs, TimeUnit.NANOSECONDS); 1545 return getFileGroupResultFuture; 1546 }); 1547 1548 MobileDataDownload mobileDataDownload = 1549 new MobileDataDownloadImpl( 1550 context, 1551 fakeEventLogger, 1552 mockMobileDataDownloadManager, 1553 controlExecutor, 1554 /* fileGroupPopulatorList= */ ImmutableList.of(), 1555 Optional.of(mockTaskScheduler), 1556 fileStorage, 1557 /* downloadMonitorOptional= */ Optional.absent(), 1558 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1559 flags, 1560 singleFileDownloader, 1561 /* customValidatorOptional= */ Optional.absent(), 1562 timeSource); 1563 1564 Throwable thrown = 1565 assertThrows( 1566 expectedThrowable, 1567 () -> 1568 mobileDataDownload 1569 .getFileGroup( 1570 GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 1571 .get()); 1572 1573 if (thrown instanceof ExecutionException) { 1574 assertThat(thrown).hasCauseThat().isInstanceOf(causeThrowable); 1575 } 1576 } 1577 1578 @Test getFileGroup_throwsCancelledException_logsCancelled()1579 public void getFileGroup_throwsCancelledException_logsCancelled() throws Exception { 1580 getFileGroupErrorLoggingTestHelper( 1581 Futures.immediateCancelledFuture(), CancellationException.class, null, 0); 1582 } 1583 1584 @Test getFileGroup_throwsUnknownException_logsFailureWithoutCause()1585 public void getFileGroup_throwsUnknownException_logsFailureWithoutCause() throws Exception { 1586 getFileGroupErrorLoggingTestHelper( 1587 Futures.immediateFailedFuture(new Exception()), 1588 ExecutionException.class, 1589 Exception.class, 1590 0); 1591 } 1592 1593 @Test getFileGroup_throwsInterruptedException_logsInterrupted()1594 public void getFileGroup_throwsInterruptedException_logsInterrupted() throws Exception { 1595 getFileGroupErrorLoggingTestHelper( 1596 Futures.immediateFailedFuture(new InterruptedException()), 1597 ExecutionException.class, 1598 InterruptedException.class, 1599 0); 1600 } 1601 1602 @Test getFileGroup_throwsIOException_logsIOError()1603 public void getFileGroup_throwsIOException_logsIOError() throws Exception { 1604 getFileGroupErrorLoggingTestHelper( 1605 Futures.immediateFailedFuture(new IOException()), 1606 ExecutionException.class, 1607 IOException.class, 1608 0); 1609 } 1610 1611 @Test getFileGroup_throwsIllegalStateException_logsIllegalState()1612 public void getFileGroup_throwsIllegalStateException_logsIllegalState() throws Exception { 1613 getFileGroupErrorLoggingTestHelper( 1614 Futures.immediateFailedFuture(new IllegalStateException()), 1615 ExecutionException.class, 1616 IllegalStateException.class, 1617 0); 1618 } 1619 1620 @Test getFileGroup_throwsIllegalArgumentException_logsIllegalArgument()1621 public void getFileGroup_throwsIllegalArgumentException_logsIllegalArgument() throws Exception { 1622 getFileGroupErrorLoggingTestHelper( 1623 Futures.immediateFailedFuture(new IllegalArgumentException()), 1624 ExecutionException.class, 1625 IllegalArgumentException.class, 1626 0); 1627 } 1628 1629 @Test getFileGroup_throwsUnsupportedOperationException_logsUnsupportedOperation()1630 public void getFileGroup_throwsUnsupportedOperationException_logsUnsupportedOperation() 1631 throws Exception { 1632 getFileGroupErrorLoggingTestHelper( 1633 Futures.immediateFailedFuture(new UnsupportedOperationException()), 1634 ExecutionException.class, 1635 UnsupportedOperationException.class, 1636 0); 1637 } 1638 1639 @Test getFileGroup_throwsDownloadException_logsDownloadError()1640 public void getFileGroup_throwsDownloadException_logsDownloadError() throws Exception { 1641 getFileGroupErrorLoggingTestHelper( 1642 Futures.immediateFailedFuture( 1643 DownloadException.builder() 1644 .setDownloadResultCode(DownloadResultCode.UNSPECIFIED) 1645 .build()), 1646 ExecutionException.class, 1647 DownloadException.class, 1648 0); 1649 } 1650 1651 @Test readDataFileGroup_returnsFileGroup()1652 public void readDataFileGroup_returnsFileGroup() throws Exception { 1653 DataFileGroupInternal dataFileGroupInternal = 1654 DataFileGroupInternal.newBuilder() 1655 .setGroupName(FILE_GROUP_NAME_1) 1656 .setOwnerPackage(context.getPackageName()) 1657 .addFile( 1658 MetadataProto.DataFile.newBuilder() 1659 .setFileId(FILE_ID_1) 1660 .setUrlToDownload(FILE_URL_1) 1661 .build()) 1662 .addFile( 1663 MetadataProto.DataFile.newBuilder() 1664 .setFileId(FILE_ID_2) 1665 .setUrlToDownload(FILE_URL_2) 1666 .build()) 1667 .build(); 1668 1669 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 1670 .thenReturn(Futures.immediateFuture(dataFileGroupInternal)); 1671 when(mockMobileDataDownloadManager.getDataFileUris( 1672 dataFileGroupInternal, /* verifyIsolatedStructure= */ true)) 1673 .thenReturn( 1674 Futures.immediateFuture( 1675 ImmutableMap.of( 1676 dataFileGroupInternal.getFile(0), 1677 onDeviceUri1, 1678 dataFileGroupInternal.getFile(1), 1679 onDeviceUri1))); 1680 1681 MobileDataDownload mobileDataDownload = 1682 new MobileDataDownloadImpl( 1683 context, 1684 mockEventLogger, 1685 mockMobileDataDownloadManager, 1686 controlExecutor, 1687 ImmutableList.of() /* fileGroupPopulatorList */, 1688 Optional.of(mockTaskScheduler), 1689 fileStorage, 1690 Optional.absent() /* downloadMonitorOptional */, 1691 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1692 flags, 1693 singleFileDownloader, 1694 Optional.absent() /* customFileGroupValidator */, 1695 timeSource); 1696 1697 DataFileGroup dataFileGroup = 1698 mobileDataDownload 1699 .readDataFileGroup( 1700 ReadDataFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 1701 .get(); 1702 1703 assertThat(dataFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1704 assertThat(dataFileGroup.getFileList()) 1705 .containsExactly( 1706 DataFile.newBuilder().setFileId(FILE_ID_1).setUrlToDownload(FILE_URL_1).build(), 1707 DataFile.newBuilder().setFileId(FILE_ID_2).setUrlToDownload(FILE_URL_2).build()); 1708 } 1709 1710 @Test getFileGroupsByFilter_singleGroup()1711 public void getFileGroupsByFilter_singleGroup() throws Exception { 1712 List<GroupKeyAndGroup> keyDataFileGroupList = new ArrayList<>(); 1713 1714 DataFileGroupInternal downloadedFileGroup = FILE_GROUP_INTERNAL_1; 1715 1716 GroupKey groupKey = 1717 GroupKey.newBuilder() 1718 .setGroupName(FILE_GROUP_NAME_1) 1719 .setOwnerPackage(context.getPackageName()) 1720 .build(); 1721 when(mockMobileDataDownloadManager.getFileGroup(eq(groupKey), eq(true))) 1722 .thenReturn(Futures.immediateFuture(downloadedFileGroup)); 1723 when(mockMobileDataDownloadManager.getDataFileUris( 1724 downloadedFileGroup, /* verifyIsolatedStructure= */ true)) 1725 .thenReturn( 1726 Futures.immediateFuture(ImmutableMap.of(downloadedFileGroup.getFile(0), onDeviceUri1))); 1727 keyDataFileGroupList.add( 1728 GroupKeyAndGroup.create( 1729 groupKey.toBuilder().setDownloaded(true).build(), downloadedFileGroup)); 1730 1731 DataFileGroupInternal pendingFileGroup = 1732 createDataFileGroupInternal( 1733 FILE_GROUP_NAME_1, 1734 context.getPackageName(), 1735 7 /* versionNumber */, 1736 new String[] {FILE_ID_1}, 1737 new int[] {FILE_SIZE_2}, 1738 new String[] {FILE_CHECKSUM_2}, 1739 new String[] {FILE_URL_2}, 1740 DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI); 1741 pendingFileGroup = 1742 pendingFileGroup.toBuilder() 1743 .setFile(0, pendingFileGroup.getFile(0).toBuilder().setDownloadedFileByteSize(222222)) 1744 .build(); 1745 when(mockMobileDataDownloadManager.getFileGroup(groupKey, false)) 1746 .thenReturn(Futures.immediateFuture(pendingFileGroup)); 1747 when(mockMobileDataDownloadManager.getDataFileUris( 1748 pendingFileGroup, /* verifyIsolatedStructure= */ true)) 1749 .thenReturn(Futures.immediateFuture(ImmutableMap.of())); 1750 keyDataFileGroupList.add( 1751 GroupKeyAndGroup.create( 1752 groupKey.toBuilder().setDownloaded(false).build(), pendingFileGroup)); 1753 1754 DataFileGroupInternal pendingFileGroup2 = 1755 createDataFileGroupInternal( 1756 FILE_GROUP_NAME_2, 1757 context.getPackageName(), 1758 4 /* versionNumber */, 1759 new String[] {FILE_ID_1, FILE_ID_2}, 1760 new int[] {FILE_SIZE_1, FILE_SIZE_2}, 1761 new String[] {FILE_CHECKSUM_1, FILE_CHECKSUM_2}, 1762 new String[] {FILE_URL_1, FILE_URL_2}, 1763 DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI); 1764 GroupKey groupKey2 = 1765 GroupKey.newBuilder() 1766 .setGroupName(FILE_GROUP_NAME_2) 1767 .setOwnerPackage(context.getPackageName()) 1768 .build(); 1769 when(mockMobileDataDownloadManager.getFileGroup(groupKey2, false)) 1770 .thenReturn(Futures.immediateFuture(pendingFileGroup2)); 1771 when(mockMobileDataDownloadManager.getDataFileUris( 1772 pendingFileGroup2, /* verifyIsolatedStructure= */ true)) 1773 .thenReturn(Futures.immediateFuture(ImmutableMap.of())); 1774 keyDataFileGroupList.add( 1775 GroupKeyAndGroup.create( 1776 groupKey2.toBuilder().setDownloaded(false).build(), pendingFileGroup2)); 1777 1778 when(mockMobileDataDownloadManager.getAllFreshGroups()) 1779 .thenReturn(Futures.immediateFuture(keyDataFileGroupList)); 1780 1781 MobileDataDownload mobileDataDownload = 1782 new MobileDataDownloadImpl( 1783 context, 1784 mockEventLogger, 1785 mockMobileDataDownloadManager, 1786 controlExecutor, 1787 ImmutableList.of() /* fileGroupPopulatorList */, 1788 Optional.of(mockTaskScheduler), 1789 fileStorage, 1790 Optional.absent() /* downloadMonitorOptional */, 1791 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1792 flags, 1793 singleFileDownloader, 1794 Optional.absent() /* customFileGroupValidator */, 1795 timeSource); 1796 1797 // We should get back 2 groups for FILE_GROUP_NAME_1. 1798 GetFileGroupsByFilterRequest getFileGroupsByFilterRequest = 1799 GetFileGroupsByFilterRequest.newBuilder() 1800 .setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1)) 1801 .build(); 1802 ImmutableList<ClientFileGroup> clientFileGroups = 1803 mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get(); 1804 assertThat(clientFileGroups).hasSize(2); 1805 1806 ClientFileGroup downloadedClientFileGroup = clientFileGroups.get(0); 1807 assertThat(downloadedClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1808 assertThat(downloadedClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 1809 assertThat(downloadedClientFileGroup.getVersionNumber()).isEqualTo(5); 1810 assertThat(downloadedClientFileGroup.getStatus()).isEqualTo(Status.DOWNLOADED); 1811 assertThat(downloadedClientFileGroup.getFileCount()).isEqualTo(1); 1812 assertThat(downloadedClientFileGroup.hasAccount()).isFalse(); 1813 1814 ClientFile clientFile = downloadedClientFileGroup.getFileList().get(0); 1815 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 1816 assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString()); 1817 assertThat(clientFile.getFullSizeInBytes()).isEqualTo(FILE_SIZE_1); 1818 1819 ClientFileGroup pendingClientFileGroup = clientFileGroups.get(1); 1820 assertThat(pendingClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1821 assertThat(pendingClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 1822 assertThat(pendingClientFileGroup.getVersionNumber()).isEqualTo(7); 1823 assertThat(pendingClientFileGroup.getStatus()).isEqualTo(Status.PENDING); 1824 assertThat(pendingClientFileGroup.getFileCount()).isEqualTo(1); 1825 assertThat(pendingClientFileGroup.hasAccount()).isFalse(); 1826 1827 clientFile = pendingClientFileGroup.getFileList().get(0); 1828 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 1829 assertThat(clientFile.getDownloadSizeInBytes()).isEqualTo(222222); 1830 assertThat(clientFile.getFileUri()).isEmpty(); 1831 1832 // We should get back 1 group for FILE_GROUP_NAME_2. 1833 getFileGroupsByFilterRequest = 1834 GetFileGroupsByFilterRequest.newBuilder() 1835 .setGroupNameOptional(Optional.of(FILE_GROUP_NAME_2)) 1836 .build(); 1837 clientFileGroups = mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get(); 1838 ClientFileGroup pendingClientFileGroup2 = clientFileGroups.get(0); 1839 assertThat(pendingClientFileGroup2.getGroupName()).isEqualTo(FILE_GROUP_NAME_2); 1840 assertThat(pendingClientFileGroup2.getOwnerPackage()).isEqualTo(context.getPackageName()); 1841 assertThat(pendingClientFileGroup2.getVersionNumber()).isEqualTo(4); 1842 assertThat(pendingClientFileGroup2.getStatus()).isEqualTo(Status.PENDING); 1843 assertThat(pendingClientFileGroup2.getFileCount()).isEqualTo(2); 1844 assertThat(pendingClientFileGroup2.hasAccount()).isFalse(); 1845 1846 ArgumentCaptor<DataDownloadFileGroupStats> fileGroupDetailsCaptor = 1847 ArgumentCaptor.forClass(DataDownloadFileGroupStats.class); 1848 verify(mockEventLogger, times(3)).logMddQueryStats(fileGroupDetailsCaptor.capture()); 1849 1850 List<DataDownloadFileGroupStats> fileGroupStats = fileGroupDetailsCaptor.getAllValues(); 1851 assertThat(fileGroupStats).hasSize(3); 1852 assertThat(fileGroupStats.get(0).getFileGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1853 assertThat(fileGroupStats.get(0).getOwnerPackage()).isEqualTo(context.getPackageName()); 1854 assertThat(fileGroupStats.get(0).getFileGroupVersionNumber()).isEqualTo(5); 1855 assertThat(fileGroupStats.get(0).getFileCount()).isEqualTo(1); 1856 assertThat(fileGroupStats.get(1).getFileGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1857 assertThat(fileGroupStats.get(1).getOwnerPackage()).isEqualTo(context.getPackageName()); 1858 assertThat(fileGroupStats.get(1).getFileGroupVersionNumber()).isEqualTo(7); 1859 assertThat(fileGroupStats.get(1).getFileCount()).isEqualTo(1); 1860 assertThat(fileGroupStats.get(2).getFileGroupName()).isEqualTo(FILE_GROUP_NAME_2); 1861 assertThat(fileGroupStats.get(2).getOwnerPackage()).isEqualTo(context.getPackageName()); 1862 assertThat(fileGroupStats.get(2).getFileGroupVersionNumber()).isEqualTo(4); 1863 assertThat(fileGroupStats.get(2).getFileCount()).isEqualTo(2); 1864 1865 verifyNoMoreInteractions(mockEventLogger); 1866 } 1867 1868 @Test getFileGroupsByFilter_includeAllGroups()1869 public void getFileGroupsByFilter_includeAllGroups() throws Exception { 1870 List<GroupKeyAndGroup> keyDataFileGroupList = new ArrayList<>(); 1871 1872 Account account = AccountUtil.create("account-name", "account-type"); 1873 1874 DataFileGroupInternal downloadedFileGroup = FILE_GROUP_INTERNAL_1; 1875 GroupKey groupKey = 1876 GroupKey.newBuilder() 1877 .setGroupName(FILE_GROUP_NAME_1) 1878 .setOwnerPackage(context.getPackageName()) 1879 .setAccount(AccountUtil.serialize(account)) 1880 .build(); 1881 when(mockMobileDataDownloadManager.getDataFileUris( 1882 downloadedFileGroup, /* verifyIsolatedStructure= */ true)) 1883 .thenReturn( 1884 Futures.immediateFuture(ImmutableMap.of(downloadedFileGroup.getFile(0), onDeviceUri1))); 1885 keyDataFileGroupList.add( 1886 GroupKeyAndGroup.create( 1887 groupKey.toBuilder().setDownloaded(true).build(), downloadedFileGroup)); 1888 1889 DataFileGroupInternal pendingFileGroup = 1890 createDataFileGroupInternal( 1891 FILE_GROUP_NAME_1, 1892 context.getPackageName(), 1893 7, 1894 new String[] {FILE_ID_1}, 1895 new int[] {FILE_SIZE_2}, 1896 new String[] {FILE_CHECKSUM_2}, 1897 new String[] {FILE_URL_2}, 1898 DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI); 1899 when(mockMobileDataDownloadManager.getDataFileUris( 1900 pendingFileGroup, /* verifyIsolatedStructure= */ true)) 1901 .thenReturn(Futures.immediateFuture(ImmutableMap.of())); 1902 keyDataFileGroupList.add( 1903 GroupKeyAndGroup.create( 1904 groupKey.toBuilder().setDownloaded(false).build(), pendingFileGroup)); 1905 1906 DataFileGroupInternal pendingFileGroup2 = 1907 createDataFileGroupInternal( 1908 FILE_GROUP_NAME_2, 1909 context.getPackageName(), 1910 4 /* versionNumber */, 1911 new String[] {FILE_ID_1, FILE_ID_2}, 1912 new int[] {FILE_SIZE_1, FILE_SIZE_2}, 1913 new String[] {FILE_CHECKSUM_1, FILE_CHECKSUM_2}, 1914 new String[] {FILE_URL_1, FILE_URL_2}, 1915 DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI); 1916 GroupKey groupKey2 = 1917 GroupKey.newBuilder() 1918 .setGroupName(FILE_GROUP_NAME_2) 1919 .setOwnerPackage(context.getPackageName()) 1920 .build(); 1921 when(mockMobileDataDownloadManager.getFileGroup(groupKey2, false)) 1922 .thenReturn(Futures.immediateFuture(pendingFileGroup2)); 1923 when(mockMobileDataDownloadManager.getDataFileUris( 1924 pendingFileGroup2, /* verifyIsolatedStructure= */ true)) 1925 .thenReturn(Futures.immediateFuture(ImmutableMap.of())); 1926 keyDataFileGroupList.add( 1927 GroupKeyAndGroup.create( 1928 groupKey2.toBuilder().setDownloaded(false).build(), pendingFileGroup2)); 1929 1930 when(mockMobileDataDownloadManager.getAllFreshGroups()) 1931 .thenReturn(Futures.immediateFuture(keyDataFileGroupList)); 1932 1933 MobileDataDownload mobileDataDownload = 1934 new MobileDataDownloadImpl( 1935 context, 1936 mockEventLogger, 1937 mockMobileDataDownloadManager, 1938 controlExecutor, 1939 ImmutableList.of() /* fileGroupPopulatorList */, 1940 Optional.of(mockTaskScheduler), 1941 fileStorage, 1942 Optional.of(mockDownloadMonitor), 1943 Optional.of(this.getClass()), // don't need to use the real foreground download service. 1944 flags, 1945 singleFileDownloader, 1946 Optional.absent() /* customFileGroupValidator */, 1947 timeSource); 1948 1949 // We should get back all 3 groups for this key. 1950 GetFileGroupsByFilterRequest getFileGroupsByFilterRequest = 1951 GetFileGroupsByFilterRequest.newBuilder().setIncludeAllGroups(true).build(); 1952 List<ClientFileGroup> clientFileGroups = 1953 mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get(); 1954 assertThat(clientFileGroups).hasSize(3); 1955 1956 ClientFileGroup downloadedClientFileGroup = clientFileGroups.get(0); 1957 assertThat(downloadedClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1958 assertThat(downloadedClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 1959 assertThat(downloadedClientFileGroup.getVersionNumber()).isEqualTo(5); 1960 assertThat(downloadedClientFileGroup.getStatus()).isEqualTo(Status.DOWNLOADED); 1961 assertThat(downloadedClientFileGroup.getFileCount()).isEqualTo(1); 1962 assertThat(downloadedClientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account)); 1963 1964 ClientFile clientFile = downloadedClientFileGroup.getFileList().get(0); 1965 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 1966 assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString()); 1967 assertThat(clientFile.getFullSizeInBytes()).isEqualTo(FILE_SIZE_1); 1968 1969 ClientFileGroup pendingClientFileGroup = clientFileGroups.get(1); 1970 assertThat(pendingClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1971 assertThat(pendingClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 1972 assertThat(pendingClientFileGroup.getVersionNumber()).isEqualTo(7); 1973 assertThat(pendingClientFileGroup.getStatus()).isEqualTo(Status.PENDING); 1974 assertThat(pendingClientFileGroup.getFileCount()).isEqualTo(1); 1975 assertThat(pendingClientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account)); 1976 1977 clientFile = pendingClientFileGroup.getFileList().get(0); 1978 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 1979 assertThat(clientFile.getFileUri()).isEmpty(); 1980 1981 ClientFileGroup pendingClientFileGroup2 = clientFileGroups.get(2); 1982 assertThat(pendingClientFileGroup2.getGroupName()).isEqualTo(FILE_GROUP_NAME_2); 1983 assertThat(pendingClientFileGroup2.getOwnerPackage()).isEqualTo(context.getPackageName()); 1984 assertThat(pendingClientFileGroup2.getVersionNumber()).isEqualTo(4); 1985 assertThat(pendingClientFileGroup2.getStatus()).isEqualTo(Status.PENDING); 1986 assertThat(pendingClientFileGroup2.getFileCount()).isEqualTo(2); 1987 assertThat(pendingClientFileGroup2.hasAccount()).isFalse(); 1988 1989 ArgumentCaptor<DataDownloadFileGroupStats> fileGroupDetailsCaptor = 1990 ArgumentCaptor.forClass(DataDownloadFileGroupStats.class); 1991 verify(mockEventLogger, times(3)).logMddQueryStats(fileGroupDetailsCaptor.capture()); 1992 1993 List<DataDownloadFileGroupStats> fileGroupStats = fileGroupDetailsCaptor.getAllValues(); 1994 assertThat(fileGroupStats).hasSize(3); 1995 assertThat(fileGroupStats.get(0).getFileGroupName()).isEqualTo(FILE_GROUP_NAME_1); 1996 assertThat(fileGroupStats.get(0).getOwnerPackage()).isEqualTo(context.getPackageName()); 1997 assertThat(fileGroupStats.get(0).getFileGroupVersionNumber()).isEqualTo(5); 1998 assertThat(fileGroupStats.get(0).getFileCount()).isEqualTo(1); 1999 assertThat(fileGroupStats.get(1).getFileGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2000 assertThat(fileGroupStats.get(1).getOwnerPackage()).isEqualTo(context.getPackageName()); 2001 assertThat(fileGroupStats.get(1).getFileGroupVersionNumber()).isEqualTo(7); 2002 assertThat(fileGroupStats.get(1).getFileCount()).isEqualTo(1); 2003 assertThat(fileGroupStats.get(2).getFileGroupName()).isEqualTo(FILE_GROUP_NAME_2); 2004 assertThat(fileGroupStats.get(2).getOwnerPackage()).isEqualTo(context.getPackageName()); 2005 assertThat(fileGroupStats.get(2).getFileGroupVersionNumber()).isEqualTo(4); 2006 assertThat(fileGroupStats.get(2).getFileCount()).isEqualTo(2); 2007 2008 verifyNoMoreInteractions(mockEventLogger); 2009 } 2010 2011 @Test getFileGroupsByFilter_noData()2012 public void getFileGroupsByFilter_noData() throws Exception { 2013 MobileDataDownload mobileDataDownload = 2014 new MobileDataDownloadImpl( 2015 context, 2016 mockEventLogger, 2017 mockMobileDataDownloadManager, 2018 controlExecutor, 2019 ImmutableList.of() /* fileGroupPopulatorList */, 2020 Optional.of(mockTaskScheduler), 2021 fileStorage, 2022 Optional.absent() /* downloadMonitorOptional */, 2023 Optional.of(this.getClass()), // don't need to use the real foreground download service. 2024 flags, 2025 singleFileDownloader, 2026 Optional.absent() /* customFileGroupValidator */, 2027 timeSource); 2028 when(mockMobileDataDownloadManager.getAllFreshGroups()) 2029 .thenReturn(Futures.immediateFuture(ImmutableList.of())); 2030 2031 GetFileGroupsByFilterRequest getFileGroupsByFilterRequest = 2032 GetFileGroupsByFilterRequest.newBuilder().setIncludeAllGroups(true).build(); 2033 List<ClientFileGroup> clientFileGroups = 2034 mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get(); 2035 assertThat(clientFileGroups).isEmpty(); 2036 2037 getFileGroupsByFilterRequest = 2038 GetFileGroupsByFilterRequest.newBuilder() 2039 .setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1)) 2040 .build(); 2041 clientFileGroups = mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get(); 2042 assertThat(clientFileGroups).isEmpty(); 2043 2044 verifyNoInteractions(mockEventLogger); 2045 } 2046 2047 @Test getFileGroupsByFilter_withAccount()2048 public void getFileGroupsByFilter_withAccount() throws Exception { 2049 List<GroupKeyAndGroup> keyDataFileGroupList = new ArrayList<>(); 2050 2051 Account account1 = AccountUtil.create("account-name-1", "account-type"); 2052 Account account2 = AccountUtil.create("account-name-2", "account-type"); 2053 2054 DataFileGroupInternal downloadedFileGroup = FILE_GROUP_INTERNAL_1; 2055 GroupKey groupKey = 2056 GroupKey.newBuilder() 2057 .setGroupName(FILE_GROUP_NAME_1) 2058 .setOwnerPackage(context.getPackageName()) 2059 .setAccount(AccountUtil.serialize(account1)) 2060 .build(); 2061 when(mockMobileDataDownloadManager.getFileGroup(groupKey, true)) 2062 .thenReturn(Futures.immediateFuture(downloadedFileGroup)); 2063 when(mockMobileDataDownloadManager.getDataFileUris( 2064 downloadedFileGroup, /* verifyIsolatedStructure= */ true)) 2065 .thenReturn( 2066 Futures.immediateFuture(ImmutableMap.of(downloadedFileGroup.getFile(0), onDeviceUri1))); 2067 keyDataFileGroupList.add( 2068 GroupKeyAndGroup.create( 2069 groupKey.toBuilder().setDownloaded(true).build(), downloadedFileGroup)); 2070 2071 DataFileGroupInternal pendingFileGroup = 2072 createDataFileGroupInternal( 2073 FILE_GROUP_NAME_1, 2074 context.getPackageName(), 2075 7 /* versionNumber */, 2076 new String[] {FILE_ID_1}, 2077 new int[] {FILE_SIZE_2}, 2078 new String[] {FILE_CHECKSUM_2}, 2079 new String[] {FILE_URL_2}, 2080 DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI); 2081 when(mockMobileDataDownloadManager.getFileGroup(groupKey, false)) 2082 .thenReturn(Futures.immediateFuture(pendingFileGroup)); 2083 when(mockMobileDataDownloadManager.getDataFileUris( 2084 pendingFileGroup, /* verifyIsolatedStructure= */ true)) 2085 .thenReturn(Futures.immediateFuture(ImmutableMap.of())); 2086 keyDataFileGroupList.add( 2087 GroupKeyAndGroup.create( 2088 groupKey.toBuilder().setDownloaded(false).build(), pendingFileGroup)); 2089 2090 DataFileGroupInternal pendingFileGroup2 = 2091 createDataFileGroupInternal( 2092 FILE_GROUP_NAME_1, 2093 context.getPackageName(), 2094 4 /* versionNumber */, 2095 new String[] {FILE_ID_1, FILE_ID_2}, 2096 new int[] {FILE_SIZE_1, FILE_SIZE_2}, 2097 new String[] {FILE_CHECKSUM_1, FILE_CHECKSUM_2}, 2098 new String[] {FILE_URL_1, FILE_URL_2}, 2099 DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI); 2100 GroupKey groupKey2 = 2101 GroupKey.newBuilder() 2102 .setGroupName(FILE_GROUP_NAME_1) 2103 .setOwnerPackage(context.getPackageName()) 2104 .setAccount(AccountUtil.serialize(account2)) 2105 .build(); 2106 when(mockMobileDataDownloadManager.getFileGroup(groupKey2, false)) 2107 .thenReturn(Futures.immediateFuture(pendingFileGroup2)); 2108 when(mockMobileDataDownloadManager.getDataFileUris( 2109 pendingFileGroup2, /* verifyIsolatedStructure= */ true)) 2110 .thenReturn(Futures.immediateFuture(ImmutableMap.of())); 2111 keyDataFileGroupList.add( 2112 GroupKeyAndGroup.create( 2113 groupKey2.toBuilder().setDownloaded(false).build(), pendingFileGroup2)); 2114 2115 when(mockMobileDataDownloadManager.getAllFreshGroups()) 2116 .thenReturn(Futures.immediateFuture(keyDataFileGroupList)); 2117 2118 MobileDataDownload mobileDataDownload = 2119 new MobileDataDownloadImpl( 2120 context, 2121 mockEventLogger, 2122 mockMobileDataDownloadManager, 2123 controlExecutor, 2124 ImmutableList.of() /* fileGroupPopulatorList */, 2125 Optional.of(mockTaskScheduler), 2126 fileStorage, 2127 Optional.absent() /* downloadMonitorOptional */, 2128 Optional.of(this.getClass()), // don't need to use the real foreground download service. 2129 flags, 2130 singleFileDownloader, 2131 Optional.absent() /* customFileGroupValidator */, 2132 timeSource); 2133 2134 // We should get back 2 groups for FILE_GROUP_NAME_1 with account1. 2135 GetFileGroupsByFilterRequest getFileGroupsByFilterRequest = 2136 GetFileGroupsByFilterRequest.newBuilder() 2137 .setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1)) 2138 .setAccountOptional(Optional.of(account1)) 2139 .build(); 2140 ImmutableList<ClientFileGroup> clientFileGroups = 2141 mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get(); 2142 assertThat(clientFileGroups).hasSize(2); 2143 2144 ClientFileGroup downloadedClientFileGroup = clientFileGroups.get(0); 2145 assertThat(downloadedClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2146 assertThat(downloadedClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 2147 assertThat(downloadedClientFileGroup.getVersionNumber()).isEqualTo(5); 2148 assertThat(downloadedClientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account1)); 2149 assertThat(downloadedClientFileGroup.getStatus()).isEqualTo(Status.DOWNLOADED); 2150 assertThat(downloadedClientFileGroup.getFileCount()).isEqualTo(1); 2151 2152 ClientFile clientFile = downloadedClientFileGroup.getFileList().get(0); 2153 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 2154 assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString()); 2155 assertThat(clientFile.getFullSizeInBytes()).isEqualTo(FILE_SIZE_1); 2156 2157 ClientFileGroup pendingClientFileGroup = clientFileGroups.get(1); 2158 assertThat(pendingClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2159 assertThat(pendingClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 2160 assertThat(pendingClientFileGroup.getVersionNumber()).isEqualTo(7); 2161 assertThat(pendingClientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account1)); 2162 assertThat(pendingClientFileGroup.getStatus()).isEqualTo(Status.PENDING); 2163 assertThat(pendingClientFileGroup.getFileCount()).isEqualTo(1); 2164 2165 clientFile = pendingClientFileGroup.getFileList().get(0); 2166 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 2167 assertThat(clientFile.getFileUri()).isEmpty(); 2168 2169 // We should get back 1 group for FILE_GROUP_NAME_1 with account2. 2170 getFileGroupsByFilterRequest = 2171 GetFileGroupsByFilterRequest.newBuilder() 2172 .setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1)) 2173 .setAccountOptional(Optional.of(account2)) 2174 .build(); 2175 clientFileGroups = mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get(); 2176 ClientFileGroup pendingClientFileGroup2 = clientFileGroups.get(0); 2177 assertThat(pendingClientFileGroup2.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2178 assertThat(pendingClientFileGroup2.getOwnerPackage()).isEqualTo(context.getPackageName()); 2179 assertThat(pendingClientFileGroup2.getVersionNumber()).isEqualTo(4); 2180 assertThat(pendingClientFileGroup2.getAccount()).isEqualTo(AccountUtil.serialize(account2)); 2181 assertThat(pendingClientFileGroup2.getStatus()).isEqualTo(Status.PENDING); 2182 assertThat(pendingClientFileGroup2.getFileCount()).isEqualTo(2); 2183 2184 ArgumentCaptor<DataDownloadFileGroupStats> fileGroupDetailsCaptor = 2185 ArgumentCaptor.forClass(DataDownloadFileGroupStats.class); 2186 verify(mockEventLogger, times(3)).logMddQueryStats(fileGroupDetailsCaptor.capture()); 2187 2188 List<DataDownloadFileGroupStats> fileGroupStats = fileGroupDetailsCaptor.getAllValues(); 2189 assertThat(fileGroupStats).hasSize(3); 2190 assertThat(fileGroupStats.get(0).getFileGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2191 assertThat(fileGroupStats.get(0).getOwnerPackage()).isEqualTo(context.getPackageName()); 2192 assertThat(fileGroupStats.get(0).getFileGroupVersionNumber()).isEqualTo(5); 2193 assertThat(fileGroupStats.get(0).getFileCount()).isEqualTo(1); 2194 assertThat(fileGroupStats.get(1).getFileGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2195 assertThat(fileGroupStats.get(1).getOwnerPackage()).isEqualTo(context.getPackageName()); 2196 assertThat(fileGroupStats.get(1).getFileGroupVersionNumber()).isEqualTo(7); 2197 assertThat(fileGroupStats.get(1).getFileCount()).isEqualTo(1); 2198 assertThat(fileGroupStats.get(2).getFileGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2199 assertThat(fileGroupStats.get(2).getOwnerPackage()).isEqualTo(context.getPackageName()); 2200 assertThat(fileGroupStats.get(2).getFileGroupVersionNumber()).isEqualTo(4); 2201 assertThat(fileGroupStats.get(2).getFileCount()).isEqualTo(2); 2202 2203 verifyNoMoreInteractions(mockEventLogger); 2204 } 2205 2206 @Test getFileGroupsByFilter_groupWithNoAccountOnly()2207 public void getFileGroupsByFilter_groupWithNoAccountOnly() throws Exception { 2208 List<GroupKeyAndGroup> keyDataFileGroupList = new ArrayList<>(); 2209 2210 Account account1 = AccountUtil.create("account-name-1", "account-type"); 2211 Account account2 = AccountUtil.create("account-name-2", "account-type"); 2212 2213 // downloadedFileGroup is associated with account1. 2214 DataFileGroupInternal downloadedFileGroup = FILE_GROUP_INTERNAL_1; 2215 GroupKey groupKey = 2216 GroupKey.newBuilder() 2217 .setGroupName(FILE_GROUP_NAME_1) 2218 .setOwnerPackage(context.getPackageName()) 2219 .setAccount(AccountUtil.serialize(account1)) 2220 .build(); 2221 when(mockMobileDataDownloadManager.getFileGroup(groupKey, true)) 2222 .thenReturn(Futures.immediateFuture(downloadedFileGroup)); 2223 when(mockMobileDataDownloadManager.getDataFileUris( 2224 downloadedFileGroup, /* verifyIsolatedStructure= */ true)) 2225 .thenReturn( 2226 Futures.immediateFuture(ImmutableMap.of(downloadedFileGroup.getFile(0), onDeviceUri1))); 2227 keyDataFileGroupList.add( 2228 GroupKeyAndGroup.create( 2229 groupKey.toBuilder().setDownloaded(true).build(), downloadedFileGroup)); 2230 2231 // pendingFileGroup is associated with account2. 2232 DataFileGroupInternal pendingFileGroup = 2233 createDataFileGroupInternal( 2234 FILE_GROUP_NAME_1, 2235 context.getPackageName(), 2236 /* versionNumber= */ 7, 2237 new String[] {FILE_ID_1}, 2238 new int[] {FILE_SIZE_2}, 2239 new String[] {FILE_CHECKSUM_2}, 2240 new String[] {FILE_URL_2}, 2241 DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI); 2242 GroupKey groupKey2 = 2243 GroupKey.newBuilder() 2244 .setGroupName(FILE_GROUP_NAME_1) 2245 .setOwnerPackage(context.getPackageName()) 2246 .setAccount(AccountUtil.serialize(account2)) 2247 .build(); 2248 when(mockMobileDataDownloadManager.getFileGroup(groupKey2, false)) 2249 .thenReturn(Futures.immediateFuture(pendingFileGroup)); 2250 when(mockMobileDataDownloadManager.getDataFileUris( 2251 pendingFileGroup, /* verifyIsolatedStructure= */ true)) 2252 .thenReturn(Futures.immediateFuture(ImmutableMap.of())); 2253 keyDataFileGroupList.add( 2254 GroupKeyAndGroup.create( 2255 groupKey2.toBuilder().setDownloaded(false).build(), pendingFileGroup)); 2256 2257 // pendingFileGroup2 is an account independent group. 2258 DataFileGroupInternal pendingFileGroup2 = 2259 createDataFileGroupInternal( 2260 FILE_GROUP_NAME_1, 2261 context.getPackageName(), 2262 /* versionNumber= */ 4, 2263 new String[] {FILE_ID_1, FILE_ID_2}, 2264 new int[] {FILE_SIZE_1, FILE_SIZE_2}, 2265 new String[] {FILE_CHECKSUM_1, FILE_CHECKSUM_2}, 2266 new String[] {FILE_URL_1, FILE_URL_2}, 2267 DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI); 2268 GroupKey groupKey3 = 2269 GroupKey.newBuilder() 2270 .setGroupName(FILE_GROUP_NAME_1) 2271 .setOwnerPackage(context.getPackageName()) 2272 .build(); 2273 when(mockMobileDataDownloadManager.getFileGroup(groupKey3, false)) 2274 .thenReturn(Futures.immediateFuture(pendingFileGroup2)); 2275 when(mockMobileDataDownloadManager.getDataFileUris( 2276 pendingFileGroup2, /* verifyIsolatedStructure= */ true)) 2277 .thenReturn(Futures.immediateFuture(ImmutableMap.of())); 2278 keyDataFileGroupList.add( 2279 GroupKeyAndGroup.create( 2280 groupKey3.toBuilder().setDownloaded(false).build(), pendingFileGroup2)); 2281 2282 when(mockMobileDataDownloadManager.getAllFreshGroups()) 2283 .thenReturn(Futures.immediateFuture(keyDataFileGroupList)); 2284 2285 MobileDataDownload mobileDataDownload = 2286 new MobileDataDownloadImpl( 2287 context, 2288 mockEventLogger, 2289 mockMobileDataDownloadManager, 2290 controlExecutor, 2291 /* fileGroupPopulatorList= */ ImmutableList.of(), 2292 Optional.of(mockTaskScheduler), 2293 fileStorage, 2294 /* downloadMonitorOptional= */ Optional.absent(), 2295 /* foregroundDownloadServiceClassOptional= */ Optional.absent(), 2296 flags, 2297 singleFileDownloader, 2298 Optional.absent() /* customFileGroupValidator */, 2299 timeSource); 2300 2301 // We should get back only 1 group for FILE_GROUP_NAME_1 with groupWithNoAccountOnly being set 2302 // to true. 2303 GetFileGroupsByFilterRequest getFileGroupsByFilterRequest = 2304 GetFileGroupsByFilterRequest.newBuilder() 2305 .setGroupWithNoAccountOnly(true) 2306 .setGroupNameOptional(Optional.of(FILE_GROUP_NAME_1)) 2307 .build(); 2308 ImmutableList<ClientFileGroup> clientFileGroups = 2309 mobileDataDownload.getFileGroupsByFilter(getFileGroupsByFilterRequest).get(); 2310 assertThat(clientFileGroups).hasSize(1); 2311 2312 ClientFileGroup pendingClientFileGroup = clientFileGroups.get(0); 2313 assertThat(pendingClientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2314 assertThat(pendingClientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 2315 assertThat(pendingClientFileGroup.getVersionNumber()).isEqualTo(4); 2316 assertThat(pendingClientFileGroup.getStatus()).isEqualTo(Status.PENDING); 2317 assertThat(pendingClientFileGroup.getFileCount()).isEqualTo(2); 2318 assertThat(pendingClientFileGroup.hasAccount()).isFalse(); 2319 2320 ArgumentCaptor<DataDownloadFileGroupStats> fileGroupDetailsCaptor = 2321 ArgumentCaptor.forClass(DataDownloadFileGroupStats.class); 2322 verify(mockEventLogger, times(1)).logMddQueryStats(fileGroupDetailsCaptor.capture()); 2323 2324 List<DataDownloadFileGroupStats> fileGroupStats = fileGroupDetailsCaptor.getAllValues(); 2325 assertThat(fileGroupStats).hasSize(1); 2326 assertThat(fileGroupStats.get(0).getFileGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2327 assertThat(fileGroupStats.get(0).getOwnerPackage()).isEqualTo(context.getPackageName()); 2328 assertThat(fileGroupStats.get(0).getFileGroupVersionNumber()).isEqualTo(4); 2329 assertThat(fileGroupStats.get(0).getFileCount()).isEqualTo(2); 2330 2331 verifyNoMoreInteractions(mockEventLogger); 2332 } 2333 2334 @Test importFiles_whenSuccessful_returns()2335 public void importFiles_whenSuccessful_returns() throws Exception { 2336 String inlineFileUrl = String.format("inlinefile:sha1:%s", FILE_CHECKSUM_1); 2337 DataFile inlineFile = 2338 DataFile.newBuilder() 2339 .setFileId(FILE_ID_1) 2340 .setByteSize(FILE_SIZE_1) 2341 .setChecksum(FILE_CHECKSUM_1) 2342 .setUrlToDownload(inlineFileUrl) 2343 .build(); 2344 ImmutableList<DataFile> updatedDataFileList = ImmutableList.of(inlineFile); 2345 ImmutableMap<String, FileSource> inlineFileMap = 2346 ImmutableMap.of( 2347 FILE_ID_1, FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT"))); 2348 2349 // TODO: rely on actual implementation once feature is fully implemented. 2350 when(mockMobileDataDownloadManager.importFiles( 2351 any(), anyLong(), any(), any(), any(), any(), any())) 2352 .thenReturn(Futures.immediateVoidFuture()); 2353 2354 MobileDataDownload mobileDataDownload = 2355 new MobileDataDownloadImpl( 2356 context, 2357 mockEventLogger, 2358 mockMobileDataDownloadManager, 2359 controlExecutor, 2360 /* fileGroupPopulatorList= */ ImmutableList.of(), 2361 Optional.of(mockTaskScheduler), 2362 fileStorage, 2363 Optional.of(mockDownloadMonitor), 2364 Optional.of(this.getClass()), 2365 flags, 2366 singleFileDownloader, 2367 Optional.absent() /* customFileGroupValidator */, 2368 timeSource); 2369 2370 // Since we use mocks, just call the method directly, no need to call addFileGroup first 2371 mobileDataDownload 2372 .importFiles( 2373 ImportFilesRequest.newBuilder() 2374 .setGroupName(FILE_GROUP_NAME_1) 2375 .setBuildId(1) 2376 .setVariantId("testvariant") 2377 .setUpdatedDataFileList(updatedDataFileList) 2378 .setInlineFileMap(inlineFileMap) 2379 .build()) 2380 .get(); 2381 2382 // Verify mocks were called 2383 GroupKey expectedGroupKey = 2384 GroupKey.newBuilder() 2385 .setGroupName(FILE_GROUP_NAME_1) 2386 .setOwnerPackage(context.getPackageName()) 2387 .build(); 2388 ImmutableList<MetadataProto.DataFile> expectedDataFileList = 2389 ImmutableList.of(ProtoConversionUtil.convertDataFile(inlineFile)); 2390 verify(mockMobileDataDownloadManager) 2391 .importFiles( 2392 eq(expectedGroupKey), 2393 eq(1L), 2394 eq("testvariant"), 2395 eq(expectedDataFileList), 2396 eq(inlineFileMap), 2397 eq(Optional.absent()), 2398 any()); 2399 } 2400 2401 @Test importFiles_whenAccountIsSpecified_usesAccount()2402 public void importFiles_whenAccountIsSpecified_usesAccount() throws Exception { 2403 Account account = AccountUtil.create("account-name", "account-type"); 2404 String inlineFileUrl = String.format("inlinefile:sha1:%s", FILE_CHECKSUM_1); 2405 DataFile inlineFile = 2406 DataFile.newBuilder() 2407 .setFileId(FILE_ID_1) 2408 .setByteSize(FILE_SIZE_1) 2409 .setChecksum(FILE_CHECKSUM_1) 2410 .setUrlToDownload(inlineFileUrl) 2411 .build(); 2412 ImmutableList<DataFile> updatedDataFileList = ImmutableList.of(inlineFile); 2413 ImmutableMap<String, FileSource> inlineFileMap = 2414 ImmutableMap.of( 2415 FILE_ID_1, FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT"))); 2416 2417 // TODO: rely on actual implementation once feature is fully implemented. 2418 when(mockMobileDataDownloadManager.importFiles( 2419 any(), anyLong(), any(), any(), any(), any(), any())) 2420 .thenReturn(Futures.immediateVoidFuture()); 2421 2422 MobileDataDownload mobileDataDownload = 2423 new MobileDataDownloadImpl( 2424 context, 2425 mockEventLogger, 2426 mockMobileDataDownloadManager, 2427 controlExecutor, 2428 /* fileGroupPopulatorList= */ ImmutableList.of(), 2429 Optional.of(mockTaskScheduler), 2430 fileStorage, 2431 Optional.of(mockDownloadMonitor), 2432 Optional.of(this.getClass()), 2433 flags, 2434 singleFileDownloader, 2435 Optional.absent() /* customFileGroupValidator */, 2436 timeSource); 2437 2438 // Since we use mocks, just call the method directly, no need to call addFileGroup first 2439 mobileDataDownload 2440 .importFiles( 2441 ImportFilesRequest.newBuilder() 2442 .setGroupName(FILE_GROUP_NAME_1) 2443 .setAccountOptional(Optional.of(account)) 2444 .setBuildId(1) 2445 .setVariantId("testvariant") 2446 .setUpdatedDataFileList(updatedDataFileList) 2447 .setInlineFileMap(inlineFileMap) 2448 .build()) 2449 .get(); 2450 2451 // Verify mocks were called 2452 GroupKey expectedGroupKey = 2453 GroupKey.newBuilder() 2454 .setGroupName(FILE_GROUP_NAME_1) 2455 .setAccount(AccountUtil.serialize(account)) 2456 .setOwnerPackage(context.getPackageName()) 2457 .build(); 2458 ImmutableList<MetadataProto.DataFile> expectedDataFileList = 2459 ImmutableList.of(ProtoConversionUtil.convertDataFile(inlineFile)); 2460 verify(mockMobileDataDownloadManager) 2461 .importFiles( 2462 eq(expectedGroupKey), 2463 eq(1L), 2464 eq("testvariant"), 2465 eq(expectedDataFileList), 2466 eq(inlineFileMap), 2467 eq(Optional.absent()), 2468 any()); 2469 } 2470 2471 @Test importFiles_whenFails_returnsFailure()2472 public void importFiles_whenFails_returnsFailure() throws Exception { 2473 String inlineFileUrl = String.format("inlinefile:%s", FILE_CHECKSUM_1); 2474 DataFile inlineFile = 2475 DataFile.newBuilder() 2476 .setFileId(FILE_ID_1) 2477 .setByteSize(FILE_SIZE_1) 2478 .setChecksum(FILE_CHECKSUM_1) 2479 .setUrlToDownload(inlineFileUrl) 2480 .build(); 2481 ImmutableList<DataFile> updatedDataFileList = ImmutableList.of(inlineFile); 2482 ImmutableMap<String, FileSource> inlineFileMap = 2483 ImmutableMap.of( 2484 FILE_ID_1, FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT"))); 2485 2486 // TODO: rely on actual implementation once feature is fully implemented. 2487 when(mockMobileDataDownloadManager.importFiles( 2488 any(), anyLong(), any(), any(), any(), any(), any())) 2489 .thenReturn(Futures.immediateFailedFuture(new Exception("Test failure"))); 2490 2491 MobileDataDownload mobileDataDownload = 2492 new MobileDataDownloadImpl( 2493 context, 2494 mockEventLogger, 2495 mockMobileDataDownloadManager, 2496 controlExecutor, 2497 /* fileGroupPopulatorList= */ ImmutableList.of(), 2498 Optional.of(mockTaskScheduler), 2499 fileStorage, 2500 Optional.of(mockDownloadMonitor), 2501 Optional.of(this.getClass()), 2502 flags, 2503 singleFileDownloader, 2504 Optional.absent() /* customFileGroupValidator */, 2505 timeSource); 2506 2507 // Since we use mocks, just call the method directly, no need to call addFileGroup first 2508 ExecutionException ex = 2509 assertThrows( 2510 ExecutionException.class, 2511 () -> 2512 mobileDataDownload 2513 .importFiles( 2514 ImportFilesRequest.newBuilder() 2515 .setGroupName(FILE_GROUP_NAME_1) 2516 .setBuildId(1) 2517 .setVariantId("testvariant") 2518 .setUpdatedDataFileList(updatedDataFileList) 2519 .setInlineFileMap(inlineFileMap) 2520 .build()) 2521 .get()); 2522 assertThat(ex).hasMessageThat().contains("Test failure"); 2523 2524 // Verify mocks were called 2525 GroupKey expectedGroupKey = 2526 GroupKey.newBuilder() 2527 .setGroupName(FILE_GROUP_NAME_1) 2528 .setOwnerPackage(context.getPackageName()) 2529 .build(); 2530 ImmutableList<MetadataProto.DataFile> expectedDataFileList = 2531 ImmutableList.of(ProtoConversionUtil.convertDataFile(inlineFile)); 2532 verify(mockMobileDataDownloadManager) 2533 .importFiles( 2534 eq(expectedGroupKey), 2535 eq(1L), 2536 eq("testvariant"), 2537 eq(expectedDataFileList), 2538 eq(inlineFileMap), 2539 eq(Optional.absent()), 2540 any()); 2541 } 2542 2543 @Test downloadFileGroup()2544 public void downloadFileGroup() throws Exception { 2545 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 2546 when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any())) 2547 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 2548 when(mockMobileDataDownloadManager.getFileGroup(any(), eq(false))) 2549 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 2550 when(mockMobileDataDownloadManager.getFileGroup(any(), eq(true))) 2551 .thenReturn(Futures.immediateFuture(null)); 2552 when(mockMobileDataDownloadManager.getDataFileUris( 2553 FILE_GROUP_INTERNAL_1, /* verifyIsolatedStructure= */ true)) 2554 .thenReturn( 2555 Futures.immediateFuture( 2556 ImmutableMap.of(FILE_GROUP_INTERNAL_1.getFile(0), onDeviceUri1))); 2557 2558 MobileDataDownload mobileDataDownload = 2559 new MobileDataDownloadImpl( 2560 context, 2561 mockEventLogger, 2562 mockMobileDataDownloadManager, 2563 controlExecutor, 2564 ImmutableList.of() /* fileGroupPopulatorList */, 2565 Optional.of(mockTaskScheduler), 2566 fileStorage, 2567 Optional.of(mockDownloadMonitor), 2568 Optional.of(this.getClass()), // don't need to use the real foreground download service. 2569 flags, 2570 singleFileDownloader, 2571 Optional.absent() /* customFileGroupValidator */, 2572 timeSource); 2573 2574 AtomicBoolean onCompleteInvoked = new AtomicBoolean(); 2575 2576 ClientFileGroup clientFileGroup = 2577 mobileDataDownload 2578 .downloadFileGroup( 2579 DownloadFileGroupRequest.newBuilder() 2580 .setGroupName(FILE_GROUP_NAME_1) 2581 .setListenerOptional( 2582 Optional.of( 2583 new DownloadListener() { 2584 @Override 2585 public void onProgress(long currentSize) {} 2586 2587 @Override 2588 public void onComplete(ClientFileGroup clientFileGroup) { 2589 onCompleteInvoked.set(true); 2590 assertThat(clientFileGroup.getGroupName()) 2591 .isEqualTo(FILE_GROUP_NAME_1); 2592 assertThat(clientFileGroup.getOwnerPackage()) 2593 .isEqualTo(context.getPackageName()); 2594 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 2595 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 2596 } 2597 })) 2598 .build()) 2599 .get(); 2600 2601 assertThat(onCompleteInvoked.get()).isTrue(); 2602 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2603 assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 2604 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 2605 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 2606 assertThat(clientFileGroup.hasAccount()).isFalse(); 2607 2608 ClientFile clientFile = clientFileGroup.getFileList().get(0); 2609 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 2610 assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString()); 2611 2612 verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any()); 2613 verify(mockDownloadMonitor) 2614 .addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class)); 2615 verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1)); 2616 2617 assertThat(groupKeyCaptor.getValue().getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2618 assertThat(groupKeyCaptor.getValue().hasAccount()).isFalse(); 2619 } 2620 2621 @Test downloadFileGroup_failed()2622 public void downloadFileGroup_failed() throws Exception { 2623 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 2624 when(mockMobileDataDownloadManager.getFileGroup(any(), eq(false))) 2625 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 2626 when(mockMobileDataDownloadManager.getFileGroup(any(), eq(true))) 2627 .thenReturn(Futures.immediateFuture(null)); 2628 when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any())) 2629 .thenReturn( 2630 Futures.immediateFailedFuture( 2631 DownloadException.builder() 2632 .setDownloadResultCode(DownloadResultCode.UNKNOWN_ERROR) 2633 .setMessage("Fail to download file group") 2634 .build())); 2635 2636 MobileDataDownload mobileDataDownload = 2637 new MobileDataDownloadImpl( 2638 context, 2639 mockEventLogger, 2640 mockMobileDataDownloadManager, 2641 controlExecutor, 2642 ImmutableList.of() /* fileGroupPopulatorList */, 2643 Optional.of(mockTaskScheduler), 2644 fileStorage, 2645 Optional.of(mockDownloadMonitor), 2646 Optional.of(this.getClass()), // don't need to use the real foreground download service. 2647 flags, 2648 singleFileDownloader, 2649 Optional.absent() /* customFileGroupValidator */, 2650 timeSource); 2651 2652 AtomicBoolean listenerOnFailureInvoked = new AtomicBoolean(); 2653 AtomicBoolean callbackOnFailureInvoked = new AtomicBoolean(); 2654 2655 ListenableFuture<ClientFileGroup> downloadFuture = 2656 mobileDataDownload.downloadFileGroup( 2657 DownloadFileGroupRequest.newBuilder() 2658 .setGroupName(FILE_GROUP_NAME_1) 2659 .setListenerOptional( 2660 Optional.of( 2661 new DownloadListener() { 2662 @Override 2663 public void onProgress(long currentSize) {} 2664 2665 @Override 2666 public void onComplete(ClientFileGroup clientFileGroup) {} 2667 2668 @Override 2669 public void onFailure(Throwable t) { 2670 listenerOnFailureInvoked.set(true); 2671 } 2672 })) 2673 .build()); 2674 2675 Futures.addCallback( 2676 downloadFuture, 2677 new FutureCallback<ClientFileGroup>() { 2678 @Override 2679 public void onSuccess(ClientFileGroup result) {} 2680 2681 @Override 2682 public void onFailure(Throwable t) { 2683 callbackOnFailureInvoked.set(true); 2684 } 2685 }, 2686 MoreExecutors.directExecutor()); 2687 2688 assertThrows(ExecutionException.class, downloadFuture::get); 2689 DownloadException e = LabsFutures.getFailureCauseAs(downloadFuture, DownloadException.class); 2690 assertThat(e).hasMessageThat().contains("Fail"); 2691 2692 assertThat(listenerOnFailureInvoked.get()).isTrue(); 2693 assertThat(callbackOnFailureInvoked.get()).isTrue(); 2694 verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any()); 2695 verify(mockDownloadMonitor) 2696 .addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class)); 2697 verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1)); 2698 2699 assertThat(groupKeyCaptor.getValue().getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2700 assertThat(groupKeyCaptor.getValue().hasAccount()).isFalse(); 2701 } 2702 2703 @Test downloadFileGroup_withAccount()2704 public void downloadFileGroup_withAccount() throws Exception { 2705 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 2706 when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any())) 2707 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 2708 when(mockMobileDataDownloadManager.getFileGroup(any(), eq(false))) 2709 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 2710 when(mockMobileDataDownloadManager.getFileGroup(any(), eq(true))) 2711 .thenReturn(Futures.immediateFuture(null)); 2712 when(mockMobileDataDownloadManager.getDataFileUris( 2713 FILE_GROUP_INTERNAL_1, /* verifyIsolatedStructure= */ true)) 2714 .thenReturn( 2715 Futures.immediateFuture( 2716 ImmutableMap.of(FILE_GROUP_INTERNAL_1.getFile(0), onDeviceUri1))); 2717 2718 MobileDataDownload mobileDataDownload = 2719 new MobileDataDownloadImpl( 2720 context, 2721 mockEventLogger, 2722 mockMobileDataDownloadManager, 2723 controlExecutor, 2724 ImmutableList.of() /* fileGroupPopulatorList */, 2725 Optional.of(mockTaskScheduler), 2726 fileStorage, 2727 Optional.of(mockDownloadMonitor), 2728 Optional.of(this.getClass()), // don't need to use the real foreground download service. 2729 flags, 2730 singleFileDownloader, 2731 Optional.absent() /* customFileGroupValidator */, 2732 timeSource); 2733 2734 AtomicBoolean onCompleteInvoked = new AtomicBoolean(); 2735 2736 Account account = AccountUtil.create("account-name", "account-type"); 2737 ClientFileGroup clientFileGroup = 2738 mobileDataDownload 2739 .downloadFileGroup( 2740 DownloadFileGroupRequest.newBuilder() 2741 .setGroupName(FILE_GROUP_NAME_1) 2742 .setAccountOptional(Optional.of(account)) 2743 .setListenerOptional( 2744 Optional.of( 2745 new DownloadListener() { 2746 @Override 2747 public void onProgress(long currentSize) {} 2748 2749 @Override 2750 public void onComplete(ClientFileGroup clientFileGroup) { 2751 onCompleteInvoked.set(true); 2752 assertThat(clientFileGroup.getGroupName()) 2753 .isEqualTo(FILE_GROUP_NAME_1); 2754 assertThat(clientFileGroup.getOwnerPackage()) 2755 .isEqualTo(context.getPackageName()); 2756 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 2757 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 2758 } 2759 })) 2760 .build()) 2761 .get(); 2762 2763 assertThat(onCompleteInvoked.get()).isTrue(); 2764 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2765 assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 2766 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 2767 assertThat(clientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account)); 2768 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 2769 2770 ClientFile clientFile = clientFileGroup.getFileList().get(0); 2771 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 2772 assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString()); 2773 2774 verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any()); 2775 verify(mockDownloadMonitor) 2776 .addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class)); 2777 verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1)); 2778 2779 assertThat(groupKeyCaptor.getValue().getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2780 assertThat(groupKeyCaptor.getValue().getAccount()).isEqualTo(AccountUtil.serialize(account)); 2781 } 2782 2783 @Test downloadFileGroup_withVariantId()2784 public void downloadFileGroup_withVariantId() throws Exception { 2785 DataFileGroupInternal dataFileGroup = 2786 FILE_GROUP_INTERNAL_1.toBuilder().setVariantId("en").build(); 2787 2788 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 2789 when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any())) 2790 .thenReturn(Futures.immediateFuture(dataFileGroup)); 2791 when(mockMobileDataDownloadManager.getFileGroup(any(), eq(false))) 2792 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 2793 when(mockMobileDataDownloadManager.getFileGroup(any(), eq(true))) 2794 .thenReturn(Futures.immediateFuture(null)); 2795 when(mockMobileDataDownloadManager.getDataFileUris( 2796 dataFileGroup, /* verifyIsolatedStructure= */ true)) 2797 .thenReturn( 2798 Futures.immediateFuture(ImmutableMap.of(dataFileGroup.getFile(0), onDeviceUri1))); 2799 2800 MobileDataDownload mobileDataDownload = 2801 new MobileDataDownloadImpl( 2802 context, 2803 mockEventLogger, 2804 mockMobileDataDownloadManager, 2805 controlExecutor, 2806 ImmutableList.of() /* fileGroupPopulatorList */, 2807 Optional.of(mockTaskScheduler), 2808 fileStorage, 2809 Optional.of(mockDownloadMonitor), 2810 Optional.of(this.getClass()), // don't need to use the real foreground download service. 2811 flags, 2812 singleFileDownloader, 2813 Optional.absent() /* customFileGroupValidator */, 2814 timeSource); 2815 2816 ClientFileGroup clientFileGroup = 2817 mobileDataDownload 2818 .downloadFileGroup( 2819 DownloadFileGroupRequest.newBuilder() 2820 .setGroupName(FILE_GROUP_NAME_1) 2821 .setVariantIdOptional(Optional.of("en")) 2822 .build()) 2823 .get(); 2824 2825 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2826 assertThat(clientFileGroup.getVariantId()).isEqualTo("en"); 2827 2828 verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any()); 2829 2830 GroupKey expectedGroupKey = 2831 GroupKey.newBuilder() 2832 .setGroupName(FILE_GROUP_NAME_1) 2833 .setOwnerPackage(context.getPackageName()) 2834 .setVariantId("en") 2835 .build(); 2836 assertThat(groupKeyCaptor.getValue()).isEqualTo(expectedGroupKey); 2837 } 2838 2839 @Test downloadFileGroupWithForegroundService()2840 public void downloadFileGroupWithForegroundService() throws Exception { 2841 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 2842 when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any())) 2843 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 2844 when(mockMobileDataDownloadManager.getDataFileUris( 2845 FILE_GROUP_INTERNAL_1, /* verifyIsolatedStructure= */ true)) 2846 .thenReturn( 2847 Futures.immediateFuture( 2848 ImmutableMap.of(FILE_GROUP_INTERNAL_1.getFile(0), onDeviceUri1))); 2849 when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), anyBoolean())) 2850 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 2851 2852 MobileDataDownload mobileDataDownload = 2853 new MobileDataDownloadImpl( 2854 context, 2855 mockEventLogger, 2856 mockMobileDataDownloadManager, 2857 controlExecutor, 2858 /* fileGroupPopulatorList= */ ImmutableList.of(), 2859 Optional.of(mockTaskScheduler), 2860 fileStorage, 2861 Optional.of(mockDownloadMonitor), 2862 Optional.of(this.getClass()), 2863 flags, 2864 singleFileDownloader, 2865 Optional.absent() /* customFileGroupValidator */, 2866 timeSource); 2867 2868 CountDownLatch onCompleteLatch = new CountDownLatch(1); 2869 2870 ClientFileGroup clientFileGroup = 2871 mobileDataDownload 2872 .downloadFileGroupWithForegroundService( 2873 DownloadFileGroupRequest.newBuilder() 2874 .setGroupName(FILE_GROUP_NAME_1) 2875 .setListenerOptional( 2876 Optional.of( 2877 new DownloadListener() { 2878 @Override 2879 public void onProgress(long currentSize) {} 2880 2881 @Override 2882 public void onComplete(ClientFileGroup clientFileGroup) { 2883 assertThat(clientFileGroup.getGroupName()) 2884 .isEqualTo(FILE_GROUP_NAME_1); 2885 assertThat(clientFileGroup.getOwnerPackage()) 2886 .isEqualTo(context.getPackageName()); 2887 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 2888 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 2889 2890 // This is to verify that onComplete is called. 2891 onCompleteLatch.countDown(); 2892 } 2893 })) 2894 .build()) 2895 .get(); 2896 2897 // Verify that onComplete is called. 2898 if (!onCompleteLatch.await(LATCH_WAIT_TIME_MS, TimeUnit.MILLISECONDS)) { 2899 throw new RuntimeException("onComplete is not called"); 2900 } 2901 2902 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2903 assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 2904 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 2905 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 2906 assertThat(clientFileGroup.hasAccount()).isFalse(); 2907 2908 ClientFile clientFile = clientFileGroup.getFileList().get(0); 2909 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 2910 assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString()); 2911 2912 verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any()); 2913 verify(mockDownloadMonitor) 2914 .addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class)); 2915 verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1)); 2916 2917 assertThat(groupKeyCaptor.getValue().getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2918 assertThat(groupKeyCaptor.getValue().hasAccount()).isFalse(); 2919 } 2920 2921 @Test downloadFileGroupWithForegroundService_failed()2922 public void downloadFileGroupWithForegroundService_failed() throws Exception { 2923 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 2924 when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any())) 2925 .thenReturn( 2926 Futures.immediateFailedFuture( 2927 DownloadException.builder() 2928 .setDownloadResultCode(DownloadResultCode.UNKNOWN_ERROR) 2929 .setMessage("Fail to download file group") 2930 .build())); 2931 when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(false))) 2932 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 2933 when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(true))) 2934 .thenReturn(Futures.immediateFuture(null)); 2935 2936 MobileDataDownload mobileDataDownload = 2937 new MobileDataDownloadImpl( 2938 context, 2939 mockEventLogger, 2940 mockMobileDataDownloadManager, 2941 controlExecutor, 2942 /* fileGroupPopulatorList= */ ImmutableList.of(), 2943 Optional.of(mockTaskScheduler), 2944 fileStorage, 2945 Optional.of(mockDownloadMonitor), 2946 Optional.of(this.getClass()), // don't need to use the real foreground download service. 2947 flags, 2948 singleFileDownloader, 2949 Optional.absent() /* customFileGroupValidator */, 2950 timeSource); 2951 2952 expectErrorLogMessage( 2953 "DownloadListener: onFailure:" 2954 + " com.google.android.libraries.mobiledatadownload.DownloadException: Fail to download" 2955 + " file group"); 2956 2957 ListenableFuture<ClientFileGroup> downloadFuture = 2958 mobileDataDownload.downloadFileGroupWithForegroundService( 2959 DownloadFileGroupRequest.newBuilder() 2960 .setGroupName(FILE_GROUP_NAME_1) 2961 .setListenerOptional( 2962 Optional.of( 2963 new DownloadListener() { 2964 @Override 2965 public void onProgress(long currentSize) {} 2966 2967 @Override 2968 public void onComplete(ClientFileGroup clientFileGroup) {} 2969 })) 2970 .build()); 2971 2972 AtomicBoolean onFailureInvoked = new AtomicBoolean(); 2973 Futures.addCallback( 2974 downloadFuture, 2975 new FutureCallback<ClientFileGroup>() { 2976 @Override 2977 public void onSuccess(ClientFileGroup result) {} 2978 2979 @Override 2980 public void onFailure(Throwable t) { 2981 onFailureInvoked.set(true); 2982 } 2983 }, 2984 MoreExecutors.directExecutor()); 2985 2986 assertThrows(ExecutionException.class, downloadFuture::get); 2987 DownloadException e = LabsFutures.getFailureCauseAs(downloadFuture, DownloadException.class); 2988 assertThat(e).hasMessageThat().contains("Fail"); 2989 2990 verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any()); 2991 verify(mockDownloadMonitor) 2992 .addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class)); 2993 2994 assertThat(onFailureInvoked.get()).isTrue(); 2995 verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1)); 2996 2997 assertThat(groupKeyCaptor.getValue().getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 2998 assertThat(groupKeyCaptor.getValue().hasAccount()).isFalse(); 2999 } 3000 3001 @Test downloadFileGroupWithForegroundService_withAccount()3002 public void downloadFileGroupWithForegroundService_withAccount() throws Exception { 3003 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 3004 when(mockMobileDataDownloadManager.downloadFileGroup(groupKeyCaptor.capture(), any(), any())) 3005 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 3006 when(mockMobileDataDownloadManager.getDataFileUris( 3007 FILE_GROUP_INTERNAL_1, /* verifyIsolatedStructure= */ true)) 3008 .thenReturn( 3009 Futures.immediateFuture( 3010 ImmutableMap.of(FILE_GROUP_INTERNAL_1.getFile(0), onDeviceUri1))); 3011 when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(false))) 3012 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 3013 when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(true))) 3014 .thenReturn(Futures.immediateFuture(null)); 3015 3016 MobileDataDownload mobileDataDownload = 3017 new MobileDataDownloadImpl( 3018 context, 3019 mockEventLogger, 3020 mockMobileDataDownloadManager, 3021 controlExecutor, 3022 /* fileGroupPopulatorList= */ ImmutableList.of(), 3023 Optional.of(mockTaskScheduler), 3024 fileStorage, 3025 Optional.of(mockDownloadMonitor), 3026 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3027 flags, 3028 singleFileDownloader, 3029 Optional.absent() /* customFileGroupValidator */, 3030 timeSource); 3031 3032 AtomicBoolean onCompleteInvoked = new AtomicBoolean(); 3033 Account account = AccountUtil.create("account-name", "account-type"); 3034 ClientFileGroup clientFileGroup = 3035 mobileDataDownload 3036 .downloadFileGroupWithForegroundService( 3037 DownloadFileGroupRequest.newBuilder() 3038 .setGroupName(FILE_GROUP_NAME_1) 3039 .setAccountOptional(Optional.of(account)) 3040 .setListenerOptional( 3041 Optional.of( 3042 new DownloadListener() { 3043 @Override 3044 public void onProgress(long currentSize) {} 3045 3046 @Override 3047 public void onComplete(ClientFileGroup clientFileGroup) { 3048 onCompleteInvoked.set(true); 3049 assertThat(clientFileGroup.getGroupName()) 3050 .isEqualTo(FILE_GROUP_NAME_1); 3051 assertThat(clientFileGroup.getOwnerPackage()) 3052 .isEqualTo(context.getPackageName()); 3053 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 3054 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 3055 } 3056 })) 3057 .build()) 3058 .get(); 3059 3060 assertThat(onCompleteInvoked.get()).isTrue(); 3061 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 3062 assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 3063 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 3064 assertThat(clientFileGroup.getAccount()).isEqualTo(AccountUtil.serialize(account)); 3065 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 3066 3067 ClientFile clientFile = clientFileGroup.getFileList().get(0); 3068 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 3069 assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString()); 3070 3071 verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any()); 3072 verify(mockDownloadMonitor) 3073 .addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class)); 3074 verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1)); 3075 3076 assertThat(groupKeyCaptor.getValue().getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 3077 assertThat(groupKeyCaptor.getValue().getAccount()).isEqualTo(AccountUtil.serialize(account)); 3078 } 3079 3080 @Test downloadFileGroupWithForegroundService_withVariantId()3081 public void downloadFileGroupWithForegroundService_withVariantId() throws Exception { 3082 DataFileGroupInternal dataFileGroup = 3083 FILE_GROUP_INTERNAL_1.toBuilder().setVariantId("en").build(); 3084 3085 ArgumentCaptor<GroupKey> pendingGroupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 3086 ArgumentCaptor<GroupKey> groupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 3087 ArgumentCaptor<GroupKey> downloadGroupKeyCaptor = ArgumentCaptor.forClass(GroupKey.class); 3088 when(mockMobileDataDownloadManager.downloadFileGroup( 3089 downloadGroupKeyCaptor.capture(), any(), any())) 3090 .thenReturn(Futures.immediateFuture(dataFileGroup)); 3091 when(mockMobileDataDownloadManager.getDataFileUris( 3092 dataFileGroup, /* verifyIsolatedStructure= */ true)) 3093 .thenReturn( 3094 Futures.immediateFuture(ImmutableMap.of(dataFileGroup.getFile(0), onDeviceUri1))); 3095 // The order here is important: first mock true and then false. 3096 // eq(true) returns false, and so if you mock false first, pendingGroupKeyCapture will capture 3097 // the value of groupKeyCaptor.capture(), which is null. 3098 when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), eq(true))) 3099 .thenReturn(Futures.immediateFuture(null)); 3100 when(mockMobileDataDownloadManager.getFileGroup(pendingGroupKeyCaptor.capture(), eq(false))) 3101 .thenReturn(Futures.immediateFuture(dataFileGroup)); 3102 3103 MobileDataDownload mobileDataDownload = 3104 new MobileDataDownloadImpl( 3105 context, 3106 mockEventLogger, 3107 mockMobileDataDownloadManager, 3108 controlExecutor, 3109 /* fileGroupPopulatorList= */ ImmutableList.of(), 3110 Optional.of(mockTaskScheduler), 3111 fileStorage, 3112 Optional.of(mockDownloadMonitor), 3113 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3114 flags, 3115 singleFileDownloader, 3116 Optional.absent() /* customFileGroupValidator */, 3117 timeSource); 3118 3119 ClientFileGroup clientFileGroup = 3120 mobileDataDownload 3121 .downloadFileGroupWithForegroundService( 3122 DownloadFileGroupRequest.newBuilder() 3123 .setGroupName(FILE_GROUP_NAME_1) 3124 .setVariantIdOptional(Optional.of("en")) 3125 .build()) 3126 .get(); 3127 3128 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 3129 assertThat(clientFileGroup.getVariantId()).isEqualTo("en"); 3130 3131 verify(mockMobileDataDownloadManager).downloadFileGroup(any(GroupKey.class), any(), any()); 3132 3133 GroupKey expectedGroupKey = 3134 GroupKey.newBuilder() 3135 .setGroupName(FILE_GROUP_NAME_1) 3136 .setOwnerPackage(context.getPackageName()) 3137 .setVariantId("en") 3138 .build(); 3139 assertThat(groupKeyCaptor.getAllValues()).hasSize(1); 3140 assertThat(groupKeyCaptor.getValue()).isEqualTo(expectedGroupKey); 3141 assertThat(pendingGroupKeyCaptor.getAllValues()).hasSize(1); 3142 assertThat(pendingGroupKeyCaptor.getValue()).isEqualTo(expectedGroupKey); 3143 assertThat(downloadGroupKeyCaptor.getAllValues()).hasSize(1); 3144 assertThat(downloadGroupKeyCaptor.getValue()).isEqualTo(expectedGroupKey); 3145 } 3146 3147 @Test downloadFileGroupWithForegroundService_whenAlreadyDownloaded()3148 public void downloadFileGroupWithForegroundService_whenAlreadyDownloaded() throws Exception { 3149 when(mockMobileDataDownloadManager.getDataFileUris( 3150 FILE_GROUP_INTERNAL_1, /* verifyIsolatedStructure= */ true)) 3151 .thenReturn( 3152 Futures.immediateFuture( 3153 ImmutableMap.of(FILE_GROUP_INTERNAL_1.getFile(0), onDeviceUri1))); 3154 3155 // Mock situation: no pending group but there is a downloaded group 3156 when(mockMobileDataDownloadManager.getFileGroup(any(), eq(false))) 3157 .thenReturn(Futures.immediateFuture(null)); 3158 when(mockMobileDataDownloadManager.getFileGroup(any(), eq(true))) 3159 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 3160 3161 MobileDataDownload mobileDataDownload = 3162 new MobileDataDownloadImpl( 3163 context, 3164 mockEventLogger, 3165 mockMobileDataDownloadManager, 3166 controlExecutor, 3167 /* fileGroupPopulatorList= */ ImmutableList.of(), 3168 Optional.of(mockTaskScheduler), 3169 fileStorage, 3170 Optional.of(mockDownloadMonitor), 3171 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3172 flags, 3173 singleFileDownloader, 3174 Optional.absent() /* customFileGroupValidator */, 3175 timeSource); 3176 3177 AtomicBoolean onCompleteInvoked = new AtomicBoolean(false); 3178 ClientFileGroup clientFileGroup = 3179 mobileDataDownload 3180 .downloadFileGroupWithForegroundService( 3181 DownloadFileGroupRequest.newBuilder() 3182 .setGroupName(FILE_GROUP_NAME_1) 3183 .setListenerOptional( 3184 Optional.of( 3185 new DownloadListener() { 3186 @Override 3187 public void onProgress(long currentSize) {} 3188 3189 @Override 3190 public void onComplete(ClientFileGroup clientFileGroup) { 3191 onCompleteInvoked.set(true); 3192 assertThat(clientFileGroup.getGroupName()) 3193 .isEqualTo(FILE_GROUP_NAME_1); 3194 assertThat(clientFileGroup.getOwnerPackage()) 3195 .isEqualTo(context.getPackageName()); 3196 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 3197 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 3198 } 3199 })) 3200 .build()) 3201 .get(); 3202 3203 assertThat(onCompleteInvoked.get()).isTrue(); 3204 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1); 3205 assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(context.getPackageName()); 3206 assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5); 3207 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 3208 assertThat(clientFileGroup.hasAccount()).isFalse(); 3209 3210 ClientFile clientFile = clientFileGroup.getFileList().get(0); 3211 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 3212 assertThat(clientFile.getFileUri()).isEqualTo(onDeviceUri1.toString()); 3213 3214 verify(mockMobileDataDownloadManager, times(1)).getFileGroup(any(GroupKey.class), eq(true)); 3215 verify(mockMobileDataDownloadManager, times(1)).getFileGroup(any(GroupKey.class), eq(false)); 3216 verify(mockMobileDataDownloadManager, times(0)) 3217 .downloadFileGroup(any(GroupKey.class), any(), any()); 3218 verify(mockDownloadMonitor) 3219 .addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class)); 3220 verify(mockDownloadMonitor).removeDownloadListener(eq(FILE_GROUP_NAME_1)); 3221 } 3222 3223 @Test downloadFileGroupWithForegroundService_whenNoVersionFound_fails()3224 public void downloadFileGroupWithForegroundService_whenNoVersionFound_fails() throws Exception { 3225 when(mockMobileDataDownloadManager.getFileGroup(groupKeyCaptor.capture(), anyBoolean())) 3226 .thenReturn(Futures.immediateFuture(null)); 3227 3228 MobileDataDownload mobileDataDownload = 3229 new MobileDataDownloadImpl( 3230 context, 3231 mockEventLogger, 3232 mockMobileDataDownloadManager, 3233 controlExecutor, 3234 /* fileGroupPopulatorList= */ ImmutableList.of(), 3235 Optional.of(mockTaskScheduler), 3236 fileStorage, 3237 Optional.of(mockDownloadMonitor), 3238 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3239 flags, 3240 singleFileDownloader, 3241 Optional.absent() /* customFileGroupValidator */, 3242 timeSource); 3243 3244 AtomicBoolean onFailureInvoked = new AtomicBoolean(false); 3245 ListenableFuture<ClientFileGroup> downloadFuture = 3246 mobileDataDownload.downloadFileGroupWithForegroundService( 3247 DownloadFileGroupRequest.newBuilder() 3248 .setGroupName(FILE_GROUP_NAME_1) 3249 .setListenerOptional( 3250 Optional.of( 3251 new DownloadListener() { 3252 @Override 3253 public void onProgress(long currentSize) {} 3254 3255 @Override 3256 public void onComplete(ClientFileGroup clientFileGroup) { 3257 fail("onComplete should not be called"); 3258 } 3259 3260 @Override 3261 public void onFailure(Throwable t) { 3262 onFailureInvoked.set(true); 3263 assertThat(t).isInstanceOf(DownloadException.class); 3264 assertThat(((DownloadException) t).getDownloadResultCode()) 3265 .isEqualTo(DownloadResultCode.GROUP_NOT_FOUND_ERROR); 3266 } 3267 })) 3268 .build()); 3269 3270 assertThrows(ExecutionException.class, downloadFuture::get); 3271 3272 assertThat(onFailureInvoked.get()).isTrue(); 3273 DownloadException e = LabsFutures.getFailureCauseAs(downloadFuture, DownloadException.class); 3274 assertThat(e.getDownloadResultCode()).isEqualTo(DownloadResultCode.GROUP_NOT_FOUND_ERROR); 3275 3276 // Verify did not attempt a download 3277 verify(mockMobileDataDownloadManager, times(0)) 3278 .downloadFileGroup(any(GroupKey.class), any(), any()); 3279 verify(mockDownloadMonitor, times(0)) 3280 .addDownloadListener(eq(FILE_GROUP_NAME_1), any(DownloadListener.class)); 3281 } 3282 3283 @Test maintenance_success()3284 public void maintenance_success() throws Exception { 3285 MobileDataDownload mobileDataDownload = 3286 new MobileDataDownloadImpl( 3287 context, 3288 mockEventLogger, 3289 mockMobileDataDownloadManager, 3290 controlExecutor, 3291 /* fileGroupPopulatorList= */ ImmutableList.of(), 3292 Optional.of(mockTaskScheduler), 3293 fileStorage, 3294 /* downloadMonitorOptional= */ Optional.absent(), 3295 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3296 flags, 3297 singleFileDownloader, 3298 Optional.absent() /* customFileGroupValidator */, 3299 timeSource); 3300 3301 when(mockMobileDataDownloadManager.maintenance()).thenReturn(Futures.immediateFuture(null)); 3302 3303 mobileDataDownload.maintenance().get(); 3304 3305 verify(mockMobileDataDownloadManager).maintenance(); 3306 verifyNoMoreInteractions(mockMobileDataDownloadManager); 3307 } 3308 3309 @Test maintenance_failure()3310 public void maintenance_failure() throws Exception { 3311 MobileDataDownload mobileDataDownload = 3312 new MobileDataDownloadImpl( 3313 context, 3314 mockEventLogger, 3315 mockMobileDataDownloadManager, 3316 controlExecutor, 3317 /* fileGroupPopulatorList= */ ImmutableList.of(), 3318 Optional.of(mockTaskScheduler), 3319 fileStorage, 3320 /* downloadMonitorOptional= */ Optional.absent(), 3321 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3322 flags, 3323 singleFileDownloader, 3324 Optional.absent() /* customFileGroupValidator */, 3325 timeSource); 3326 3327 when(mockMobileDataDownloadManager.maintenance()) 3328 .thenReturn(Futures.immediateFailedFuture(new IOException("test-failure"))); 3329 3330 ExecutionException e = 3331 assertThrows(ExecutionException.class, () -> mobileDataDownload.maintenance().get()); 3332 assertThat(e).hasCauseThat().isInstanceOf(IOException.class); 3333 assertThat(e).hasCauseThat().hasMessageThat().isEqualTo("test-failure"); 3334 3335 verify(mockMobileDataDownloadManager).maintenance(); 3336 verifyNoMoreInteractions(mockMobileDataDownloadManager); 3337 } 3338 3339 @Test collectGarbage_interactionTest()3340 public void collectGarbage_interactionTest() throws Exception { 3341 MobileDataDownload mobileDataDownload = 3342 new MobileDataDownloadImpl( 3343 context, 3344 mockEventLogger, 3345 mockMobileDataDownloadManager, 3346 controlExecutor, 3347 /* fileGroupPopulatorList= */ ImmutableList.of(), 3348 Optional.of(mockTaskScheduler), 3349 fileStorage, 3350 /* downloadMonitorOptional= */ Optional.absent(), 3351 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3352 flags, 3353 singleFileDownloader, 3354 Optional.absent() /* customFileGroupValidator */, 3355 timeSource); 3356 3357 when(mockMobileDataDownloadManager.removeExpiredGroupsAndFiles()) 3358 .thenReturn(Futures.immediateFuture(null)); 3359 3360 mobileDataDownload.collectGarbage().get(); 3361 3362 verify(mockMobileDataDownloadManager).removeExpiredGroupsAndFiles(); 3363 verifyNoMoreInteractions(mockMobileDataDownloadManager); 3364 } 3365 3366 @Test schedulePeriodicTasks()3367 public void schedulePeriodicTasks() throws Exception { 3368 MobileDataDownload mobileDataDownload = 3369 new MobileDataDownloadImpl( 3370 context, 3371 mockEventLogger, 3372 mockMobileDataDownloadManager, 3373 controlExecutor, 3374 /* fileGroupPopulatorList= */ ImmutableList.of(), 3375 Optional.of(mockTaskScheduler), 3376 fileStorage, 3377 /* downloadMonitorOptional= */ Optional.absent(), 3378 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3379 flags, 3380 singleFileDownloader, 3381 Optional.absent() /* customFileGroupValidator */, 3382 timeSource); 3383 3384 mobileDataDownload.schedulePeriodicTasks(); 3385 3386 verify(mockTaskScheduler) 3387 .schedulePeriodicTask( 3388 TaskScheduler.CHARGING_PERIODIC_TASK, 3389 flags.chargingGcmTaskPeriod(), 3390 NetworkState.NETWORK_STATE_ANY, 3391 /* constraintOverrides= */ Optional.absent()); 3392 3393 verify(mockTaskScheduler) 3394 .schedulePeriodicTask( 3395 TaskScheduler.MAINTENANCE_PERIODIC_TASK, 3396 flags.maintenanceGcmTaskPeriod(), 3397 NetworkState.NETWORK_STATE_ANY, 3398 /* constraintOverrides= */ Optional.absent()); 3399 3400 verify(mockTaskScheduler) 3401 .schedulePeriodicTask( 3402 TaskScheduler.CELLULAR_CHARGING_PERIODIC_TASK, 3403 flags.cellularChargingGcmTaskPeriod(), 3404 NetworkState.NETWORK_STATE_CONNECTED, 3405 /* constraintOverrides= */ Optional.absent()); 3406 3407 verify(mockTaskScheduler) 3408 .schedulePeriodicTask( 3409 TaskScheduler.WIFI_CHARGING_PERIODIC_TASK, 3410 flags.wifiChargingGcmTaskPeriod(), 3411 NetworkState.NETWORK_STATE_UNMETERED, 3412 /* constraintOverrides= */ Optional.absent()); 3413 3414 verifyNoMoreInteractions(mockTaskScheduler); 3415 } 3416 3417 @Test schedulePeriodicTasks_nullTaskScheduler()3418 public void schedulePeriodicTasks_nullTaskScheduler() throws Exception { 3419 MobileDataDownload mobileDataDownload = 3420 new MobileDataDownloadImpl( 3421 context, 3422 mockEventLogger, 3423 mockMobileDataDownloadManager, 3424 controlExecutor, 3425 /* fileGroupPopulatorList= */ ImmutableList.of(), 3426 /* taskSchedulerOptional= */ Optional.absent(), 3427 fileStorage, 3428 /* downloadMonitorOptional= */ Optional.absent(), 3429 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3430 flags, 3431 singleFileDownloader, 3432 Optional.absent() /* customFileGroupValidator */, 3433 timeSource); 3434 3435 expectErrorLogMessage( 3436 "MobileDataDownload: Called schedulePeriodicTasksInternal when taskScheduler is not" 3437 + " provided."); 3438 mobileDataDownload.schedulePeriodicTasks(); 3439 3440 verifyNoInteractions(mockTaskScheduler); 3441 } 3442 3443 @Test schedulePeriodicBackgroundTasks()3444 public void schedulePeriodicBackgroundTasks() throws Exception { 3445 MobileDataDownload mobileDataDownload = 3446 new MobileDataDownloadImpl( 3447 context, 3448 mockEventLogger, 3449 mockMobileDataDownloadManager, 3450 controlExecutor, 3451 /* fileGroupPopulatorList= */ ImmutableList.of(), 3452 Optional.of(mockTaskScheduler), 3453 fileStorage, 3454 /* downloadMonitorOptional= */ Optional.absent(), 3455 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3456 flags, 3457 singleFileDownloader, 3458 Optional.absent() /* customFileGroupValidator */, 3459 timeSource); 3460 3461 mobileDataDownload.schedulePeriodicBackgroundTasks().get(); 3462 3463 verify(mockTaskScheduler) 3464 .schedulePeriodicTask( 3465 TaskScheduler.CHARGING_PERIODIC_TASK, 3466 flags.chargingGcmTaskPeriod(), 3467 NetworkState.NETWORK_STATE_ANY, 3468 /* constraintOverrides= */ Optional.absent()); 3469 3470 verify(mockTaskScheduler) 3471 .schedulePeriodicTask( 3472 TaskScheduler.MAINTENANCE_PERIODIC_TASK, 3473 flags.maintenanceGcmTaskPeriod(), 3474 NetworkState.NETWORK_STATE_ANY, 3475 /* constraintOverrides= */ Optional.absent()); 3476 3477 verify(mockTaskScheduler) 3478 .schedulePeriodicTask( 3479 TaskScheduler.CELLULAR_CHARGING_PERIODIC_TASK, 3480 flags.cellularChargingGcmTaskPeriod(), 3481 NetworkState.NETWORK_STATE_CONNECTED, 3482 /* constraintOverrides= */ Optional.absent()); 3483 3484 verify(mockTaskScheduler) 3485 .schedulePeriodicTask( 3486 TaskScheduler.WIFI_CHARGING_PERIODIC_TASK, 3487 flags.wifiChargingGcmTaskPeriod(), 3488 NetworkState.NETWORK_STATE_UNMETERED, 3489 /* constraintOverrides= */ Optional.absent()); 3490 3491 verifyNoMoreInteractions(mockTaskScheduler); 3492 } 3493 3494 @Test schedulePeriodicBackgroundTasks_nullTaskScheduler()3495 public void schedulePeriodicBackgroundTasks_nullTaskScheduler() throws Exception { 3496 MobileDataDownload mobileDataDownload = 3497 new MobileDataDownloadImpl( 3498 context, 3499 mockEventLogger, 3500 mockMobileDataDownloadManager, 3501 controlExecutor, 3502 /* fileGroupPopulatorList= */ ImmutableList.of(), 3503 /* taskSchedulerOptional= */ Optional.absent(), 3504 fileStorage, 3505 /* downloadMonitorOptional= */ Optional.absent(), 3506 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3507 flags, 3508 singleFileDownloader, 3509 Optional.absent() /* customFileGroupValidator */, 3510 timeSource); 3511 3512 expectErrorLogMessage( 3513 "MobileDataDownload: Called schedulePeriodicTasksInternal when taskScheduler is not" 3514 + " provided."); 3515 mobileDataDownload.schedulePeriodicBackgroundTasks().get(); 3516 3517 verifyNoInteractions(mockTaskScheduler); 3518 } 3519 3520 @Test schedulePeriodicBackgroundTasks_withConstraintOverrides()3521 public void schedulePeriodicBackgroundTasks_withConstraintOverrides() throws Exception { 3522 MobileDataDownload mobileDataDownload = 3523 new MobileDataDownloadImpl( 3524 context, 3525 mockEventLogger, 3526 mockMobileDataDownloadManager, 3527 controlExecutor, 3528 /* fileGroupPopulatorList= */ ImmutableList.of(), 3529 Optional.of(mockTaskScheduler), 3530 fileStorage, 3531 /* downloadMonitorOptional= */ Optional.absent(), 3532 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3533 flags, 3534 singleFileDownloader, 3535 Optional.absent() /* customFileGroupValidator */, 3536 timeSource); 3537 3538 ConstraintOverrides wifiOverrides = 3539 ConstraintOverrides.newBuilder() 3540 .setRequiresCharging(false) 3541 .setRequiresDeviceIdle(true) 3542 .build(); 3543 ConstraintOverrides cellularOverrides = 3544 ConstraintOverrides.newBuilder() 3545 .setRequiresCharging(true) 3546 .setRequiresDeviceIdle(false) 3547 .build(); 3548 3549 Map<String, ConstraintOverrides> constraintOverridesMap = new HashMap<>(); 3550 constraintOverridesMap.put(TaskScheduler.WIFI_CHARGING_PERIODIC_TASK, wifiOverrides); 3551 constraintOverridesMap.put(TaskScheduler.CELLULAR_CHARGING_PERIODIC_TASK, cellularOverrides); 3552 3553 mobileDataDownload.schedulePeriodicBackgroundTasks(Optional.of(constraintOverridesMap)).get(); 3554 3555 verify(mockTaskScheduler) 3556 .schedulePeriodicTask( 3557 TaskScheduler.CHARGING_PERIODIC_TASK, 3558 flags.chargingGcmTaskPeriod(), 3559 NetworkState.NETWORK_STATE_ANY, 3560 Optional.absent()); 3561 3562 verify(mockTaskScheduler) 3563 .schedulePeriodicTask( 3564 TaskScheduler.MAINTENANCE_PERIODIC_TASK, 3565 flags.maintenanceGcmTaskPeriod(), 3566 NetworkState.NETWORK_STATE_ANY, 3567 Optional.absent()); 3568 3569 verify(mockTaskScheduler) 3570 .schedulePeriodicTask( 3571 TaskScheduler.CELLULAR_CHARGING_PERIODIC_TASK, 3572 flags.cellularChargingGcmTaskPeriod(), 3573 NetworkState.NETWORK_STATE_CONNECTED, 3574 Optional.of(cellularOverrides)); 3575 3576 verify(mockTaskScheduler) 3577 .schedulePeriodicTask( 3578 TaskScheduler.WIFI_CHARGING_PERIODIC_TASK, 3579 flags.wifiChargingGcmTaskPeriod(), 3580 NetworkState.NETWORK_STATE_UNMETERED, 3581 Optional.of(wifiOverrides)); 3582 3583 verifyNoMoreInteractions(mockTaskScheduler); 3584 } 3585 3586 @Test schedulePeriodicBackgroundTasks_nullTaskScheduler_andOverrides()3587 public void schedulePeriodicBackgroundTasks_nullTaskScheduler_andOverrides() throws Exception { 3588 MobileDataDownload mobileDataDownload = 3589 new MobileDataDownloadImpl( 3590 context, 3591 mockEventLogger, 3592 mockMobileDataDownloadManager, 3593 controlExecutor, 3594 /* fileGroupPopulatorList= */ ImmutableList.of(), 3595 /* taskSchedulerOptional= */ Optional.absent(), 3596 fileStorage, 3597 /* downloadMonitorOptional= */ Optional.absent(), 3598 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3599 flags, 3600 singleFileDownloader, 3601 Optional.absent() /* customFileGroupValidator */, 3602 timeSource); 3603 3604 expectErrorLogMessage( 3605 "MobileDataDownload: Called schedulePeriodicTasksInternal when taskScheduler is not" 3606 + " provided."); 3607 3608 mobileDataDownload.schedulePeriodicBackgroundTasks(Optional.absent()).get(); 3609 3610 verifyNoInteractions(mockTaskScheduler); 3611 } 3612 3613 @Test cancelPeriodicBackgroundTasks_nullTaskScheduler()3614 public void cancelPeriodicBackgroundTasks_nullTaskScheduler() throws Exception { 3615 MobileDataDownload mobileDataDownload = 3616 new MobileDataDownloadImpl( 3617 context, 3618 mockEventLogger, 3619 mockMobileDataDownloadManager, 3620 controlExecutor, 3621 /* fileGroupPopulatorList= */ ImmutableList.of(), 3622 /* taskSchedulerOptional= */ Optional.absent(), 3623 fileStorage, 3624 /* downloadMonitorOptional= */ Optional.absent(), 3625 Optional.absent() /* foregroundDownloadServiceClassOptional */, 3626 flags, 3627 singleFileDownloader, 3628 Optional.absent() /* customFileGroupValidator */, 3629 timeSource); 3630 3631 mobileDataDownload.cancelPeriodicBackgroundTasks().get(); 3632 3633 verifyNoInteractions(mockTaskScheduler); 3634 } 3635 3636 @Test cancelPeriodicBackgroundTasks()3637 public void cancelPeriodicBackgroundTasks() throws Exception { 3638 MobileDataDownload mobileDataDownload = 3639 new MobileDataDownloadImpl( 3640 context, 3641 mockEventLogger, 3642 mockMobileDataDownloadManager, 3643 controlExecutor, 3644 /* fileGroupPopulatorList= */ ImmutableList.of(), 3645 Optional.of(mockTaskScheduler), 3646 fileStorage, 3647 /* downloadMonitorOptional= */ Optional.absent(), 3648 Optional.absent() /* foregroundDownloadServiceClassOptional */, 3649 flags, 3650 singleFileDownloader, 3651 Optional.absent() /* customFileGroupValidator */, 3652 timeSource); 3653 3654 mobileDataDownload.cancelPeriodicBackgroundTasks().get(); 3655 3656 verify(mockTaskScheduler).cancelPeriodicTask(TaskScheduler.CHARGING_PERIODIC_TASK); 3657 3658 verify(mockTaskScheduler).cancelPeriodicTask(TaskScheduler.MAINTENANCE_PERIODIC_TASK); 3659 3660 verify(mockTaskScheduler).cancelPeriodicTask(TaskScheduler.CELLULAR_CHARGING_PERIODIC_TASK); 3661 3662 verify(mockTaskScheduler).cancelPeriodicTask(TaskScheduler.WIFI_CHARGING_PERIODIC_TASK); 3663 3664 verifyNoMoreInteractions(mockTaskScheduler); 3665 } 3666 3667 // A helper function to create a DataFilegroup. createDataFileGroup( String groupName, String ownerPackage, int versionNumber, String[] fileId, int[] byteSize, String[] checksum, String[] url, DeviceNetworkPolicy deviceNetworkPolicy)3668 private static DataFileGroup createDataFileGroup( 3669 String groupName, 3670 String ownerPackage, 3671 int versionNumber, 3672 String[] fileId, 3673 int[] byteSize, 3674 String[] checksum, 3675 String[] url, 3676 DeviceNetworkPolicy deviceNetworkPolicy) { 3677 if (fileId.length != byteSize.length 3678 || fileId.length != checksum.length 3679 || fileId.length != url.length) { 3680 throw new IllegalArgumentException(); 3681 } 3682 3683 DataFileGroup.Builder dataFileGroupBuilder = 3684 DataFileGroup.newBuilder() 3685 .setGroupName(groupName) 3686 .setOwnerPackage(ownerPackage) 3687 .setFileGroupVersionNumber(versionNumber) 3688 .setDownloadConditions( 3689 DownloadConditions.newBuilder().setDeviceNetworkPolicy(deviceNetworkPolicy)); 3690 3691 for (int i = 0; i < fileId.length; ++i) { 3692 DataFile file = 3693 DataFile.newBuilder() 3694 .setFileId(fileId[i]) 3695 .setByteSize(byteSize[i]) 3696 .setChecksum(checksum[i]) 3697 .setUrlToDownload(url[i]) 3698 .build(); 3699 dataFileGroupBuilder.addFile(file); 3700 } 3701 3702 return dataFileGroupBuilder.build(); 3703 } 3704 createDataFileGroupInternal( String groupName, String ownerPackage, int versionNumber, String[] fileId, int[] byteSize, String[] checksum, String[] url, DeviceNetworkPolicy deviceNetworkPolicy)3705 private static DataFileGroupInternal createDataFileGroupInternal( 3706 String groupName, 3707 String ownerPackage, 3708 int versionNumber, 3709 String[] fileId, 3710 int[] byteSize, 3711 String[] checksum, 3712 String[] url, 3713 DeviceNetworkPolicy deviceNetworkPolicy) { 3714 try { 3715 return ProtoConversionUtil.convert( 3716 createDataFileGroup( 3717 groupName, 3718 ownerPackage, 3719 versionNumber, 3720 fileId, 3721 byteSize, 3722 checksum, 3723 url, 3724 deviceNetworkPolicy)); 3725 } catch (Exception e) { 3726 // wrap with runtime exception to avoid this method having to declare throws 3727 throw new RuntimeException(e); 3728 } 3729 } 3730 3731 @Test handleTask_maintenance()3732 public void handleTask_maintenance() throws Exception { 3733 MobileDataDownload mobileDataDownload = 3734 new MobileDataDownloadImpl( 3735 context, 3736 mockEventLogger, 3737 mockMobileDataDownloadManager, 3738 controlExecutor, 3739 /* fileGroupPopulatorList= */ ImmutableList.of(), 3740 Optional.of(mockTaskScheduler), 3741 fileStorage, 3742 /* downloadMonitorOptional= */ Optional.absent(), 3743 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3744 flags, 3745 singleFileDownloader, 3746 Optional.absent() /* customFileGroupValidator */, 3747 timeSource); 3748 when(mockMobileDataDownloadManager.maintenance()).thenReturn(Futures.immediateFuture(null)); 3749 3750 mobileDataDownload.handleTask(TaskScheduler.MAINTENANCE_PERIODIC_TASK).get(); 3751 verify(mockMobileDataDownloadManager).maintenance(); 3752 verifyNoMoreInteractions(mockMobileDataDownloadManager); 3753 } 3754 3755 @Test handleTask_charging()3756 public void handleTask_charging() throws Exception { 3757 MobileDataDownload mobileDataDownload = 3758 new MobileDataDownloadImpl( 3759 context, 3760 mockEventLogger, 3761 mockMobileDataDownloadManager, 3762 controlExecutor, 3763 ImmutableList.of(mockFileGroupPopulator), 3764 Optional.of(mockTaskScheduler), 3765 fileStorage, 3766 /* downloadMonitorOptional= */ Optional.absent(), 3767 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3768 flags, 3769 singleFileDownloader, 3770 Optional.absent() /* customFileGroupValidator */, 3771 timeSource); 3772 3773 when(mockMobileDataDownloadManager.verifyAllPendingGroups(any())) 3774 .thenReturn(Futures.immediateFuture(null)); 3775 when(mockFileGroupPopulator.refreshFileGroups(mobileDataDownload)) 3776 .thenReturn(Futures.immediateFuture(null)); 3777 3778 mobileDataDownload.handleTask(TaskScheduler.CHARGING_PERIODIC_TASK).get(); 3779 verify(mockFileGroupPopulator).refreshFileGroups(mobileDataDownload); 3780 verify(mockMobileDataDownloadManager).verifyAllPendingGroups(any()); 3781 verifyNoMoreInteractions(mockMobileDataDownloadManager); 3782 } 3783 3784 @Test handleTask_wifi_charging()3785 public void handleTask_wifi_charging() throws Exception { 3786 MobileDataDownload mobileDataDownload = 3787 new MobileDataDownloadImpl( 3788 context, 3789 mockEventLogger, 3790 mockMobileDataDownloadManager, 3791 controlExecutor, 3792 ImmutableList.of(mockFileGroupPopulator), 3793 Optional.of(mockTaskScheduler), 3794 fileStorage, 3795 /* downloadMonitorOptional= */ Optional.absent(), 3796 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3797 flags, 3798 singleFileDownloader, 3799 Optional.absent() /* customFileGroupValidator */, 3800 timeSource); 3801 3802 when(mockFileGroupPopulator.refreshFileGroups(mobileDataDownload)) 3803 .thenReturn(Futures.immediateFuture(null)); 3804 when(mockMobileDataDownloadManager.downloadAllPendingGroups(eq(true) /*wifi*/, any())) 3805 .thenReturn(Futures.immediateFuture(null)); 3806 3807 mobileDataDownload.handleTask(TaskScheduler.WIFI_CHARGING_PERIODIC_TASK).get(); 3808 verify(mockFileGroupPopulator, times(2)).refreshFileGroups(mobileDataDownload); 3809 verify(mockMobileDataDownloadManager, times(2)).downloadAllPendingGroups(eq(true), any()); 3810 verifyNoMoreInteractions(mockMobileDataDownloadManager); 3811 } 3812 3813 @Test handleTask_cellular_charging()3814 public void handleTask_cellular_charging() throws Exception { 3815 MobileDataDownload mobileDataDownload = 3816 new MobileDataDownloadImpl( 3817 context, 3818 mockEventLogger, 3819 mockMobileDataDownloadManager, 3820 controlExecutor, 3821 ImmutableList.of(mockFileGroupPopulator), 3822 Optional.of(mockTaskScheduler), 3823 fileStorage, 3824 /* downloadMonitorOptional= */ Optional.absent(), 3825 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3826 flags, 3827 singleFileDownloader, 3828 Optional.absent() /* customFileGroupValidator */, 3829 timeSource); 3830 3831 when(mockFileGroupPopulator.refreshFileGroups(mobileDataDownload)) 3832 .thenReturn(Futures.immediateFuture(null)); 3833 when(mockMobileDataDownloadManager.downloadAllPendingGroups(eq(false) /*wifi*/, any())) 3834 .thenReturn(Futures.immediateFuture(null)); 3835 3836 mobileDataDownload.handleTask(TaskScheduler.CELLULAR_CHARGING_PERIODIC_TASK).get(); 3837 verify(mockFileGroupPopulator, times(2)).refreshFileGroups(mobileDataDownload); 3838 verify(mockMobileDataDownloadManager, times(2)).downloadAllPendingGroups(eq(false), any()); 3839 verifyNoMoreInteractions(mockMobileDataDownloadManager); 3840 } 3841 3842 @Test handleTask_no_filegroup_populator()3843 public void handleTask_no_filegroup_populator() throws Exception { 3844 MobileDataDownload mobileDataDownload = 3845 new MobileDataDownloadImpl( 3846 context, 3847 mockEventLogger, 3848 mockMobileDataDownloadManager, 3849 controlExecutor, 3850 /* fileGroupPopulatorList= */ ImmutableList.of(), 3851 Optional.of(mockTaskScheduler), 3852 fileStorage, 3853 /* downloadMonitorOptional= */ Optional.absent(), 3854 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3855 flags, 3856 singleFileDownloader, 3857 Optional.absent() /* customFileGroupValidator */, 3858 timeSource); 3859 3860 when(mockMobileDataDownloadManager.verifyAllPendingGroups(any())) 3861 .thenReturn(Futures.immediateFuture(null)); 3862 when(mockMobileDataDownloadManager.downloadAllPendingGroups(anyBoolean() /*wifi*/, any())) 3863 .thenReturn(Futures.immediateFuture(null)); 3864 3865 mobileDataDownload.handleTask(TaskScheduler.CHARGING_PERIODIC_TASK).get(); 3866 verify(mockMobileDataDownloadManager).verifyAllPendingGroups(any()); 3867 3868 mobileDataDownload.handleTask(TaskScheduler.CELLULAR_CHARGING_PERIODIC_TASK).get(); 3869 verify(mockMobileDataDownloadManager, times(2)).downloadAllPendingGroups(eq(false), any()); 3870 3871 mobileDataDownload.handleTask(TaskScheduler.WIFI_CHARGING_PERIODIC_TASK).get(); 3872 verify(mockMobileDataDownloadManager, times(2)).downloadAllPendingGroups(eq(true), any()); 3873 } 3874 3875 @Test handleTask_invalid_tag()3876 public void handleTask_invalid_tag() throws Exception { 3877 MobileDataDownload mobileDataDownload = 3878 new MobileDataDownloadImpl( 3879 context, 3880 mockEventLogger, 3881 mockMobileDataDownloadManager, 3882 controlExecutor, 3883 ImmutableList.of(mockFileGroupPopulator), 3884 Optional.of(mockTaskScheduler), 3885 fileStorage, 3886 /* downloadMonitorOptional= */ Optional.absent(), 3887 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3888 flags, 3889 singleFileDownloader, 3890 Optional.absent() /* customFileGroupValidator */, 3891 timeSource); 3892 3893 ExecutionException e = 3894 assertThrows( 3895 ExecutionException.class, () -> mobileDataDownload.handleTask("invalid-tag").get()); 3896 assertThat(e).hasCauseThat().isInstanceOf(IllegalArgumentException.class); 3897 } 3898 3899 @Test handleTask_onePopulatorFails_continuesToRunOthers()3900 public void handleTask_onePopulatorFails_continuesToRunOthers() throws Exception { 3901 FileGroupPopulator failingPopulator = 3902 (MobileDataDownload unused) -> 3903 Futures.immediateFailedFuture(new IllegalArgumentException("test")); 3904 3905 AtomicBoolean refreshedOneSucceedingPopulator = new AtomicBoolean(false); 3906 FileGroupPopulator oneSucceedingPopulator = 3907 (MobileDataDownload unused) -> { 3908 refreshedOneSucceedingPopulator.set(true); 3909 return Futures.immediateVoidFuture(); 3910 }; 3911 3912 AtomicBoolean refreshedAnotherSucceedingPopulator = new AtomicBoolean(false); 3913 FileGroupPopulator anotherSucceedingPopulator = 3914 (MobileDataDownload unused) -> { 3915 refreshedAnotherSucceedingPopulator.set(true); 3916 return Futures.immediateVoidFuture(); 3917 }; 3918 3919 // The populators will be executed in this order. 3920 ImmutableList<FileGroupPopulator> populators = 3921 ImmutableList.of(failingPopulator, oneSucceedingPopulator, anotherSucceedingPopulator); 3922 3923 MobileDataDownload mobileDataDownload = 3924 new MobileDataDownloadImpl( 3925 context, 3926 mockEventLogger, 3927 mockMobileDataDownloadManager, 3928 controlExecutor, 3929 populators, 3930 Optional.of(mockTaskScheduler), 3931 fileStorage, 3932 /* downloadMonitorOptional= */ Optional.absent(), 3933 Optional.of(this.getClass()), // don't need to use the real foreground download service. 3934 flags, 3935 singleFileDownloader, 3936 Optional.absent() /* customFileGroupValidator */, 3937 timeSource); 3938 3939 when(mockMobileDataDownloadManager.verifyAllPendingGroups(any() /* validator */)) 3940 .thenReturn(Futures.immediateVoidFuture()); 3941 when(mockMobileDataDownloadManager.downloadAllPendingGroups( 3942 anyBoolean() /*wifi*/, any() /* validator */)) 3943 .thenReturn(Futures.immediateVoidFuture()); 3944 3945 ListenableFuture<Void> handleFuture = 3946 mobileDataDownload.handleTask(TaskScheduler.WIFI_CHARGING_PERIODIC_TASK); 3947 assertThat(handleFuture).whenDone().isSuccessful(); 3948 3949 handleFuture.get(); 3950 assertThat(refreshedOneSucceedingPopulator.get()).isTrue(); 3951 assertThat(refreshedAnotherSucceedingPopulator.get()).isTrue(); 3952 } 3953 3954 @Test reportUsage_basic()3955 public void reportUsage_basic() throws Exception { 3956 when(mockMobileDataDownloadManager.getFileGroup(any(GroupKey.class), eq(true))) 3957 .thenReturn(Futures.immediateFuture(FILE_GROUP_INTERNAL_1)); 3958 when(mockMobileDataDownloadManager.getDataFileUris( 3959 FILE_GROUP_INTERNAL_1, /* verifyIsolatedStructure= */ true)) 3960 .thenReturn( 3961 Futures.immediateFuture( 3962 ImmutableMap.of(FILE_GROUP_INTERNAL_1.getFile(0), onDeviceUri1))); 3963 3964 MobileDataDownload mobileDataDownload = createDefaultMobileDataDownload(); 3965 3966 ClientFileGroup clientFileGroup = 3967 mobileDataDownload 3968 .getFileGroup(GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_NAME_1).build()) 3969 .get(); 3970 3971 UsageEvent usageEvent = 3972 UsageEvent.builder() 3973 .setEventCode(0) 3974 .setAppVersion(123) 3975 .setClientFileGroup(clientFileGroup) 3976 .build(); 3977 mobileDataDownload.reportUsage(usageEvent).get(); 3978 3979 verify(mockEventLogger).logMddUsageEvent(createFileGroupStats(clientFileGroup), null); 3980 } 3981 createFileGroupStats(ClientFileGroup clientFileGroup)3982 private static DataDownloadFileGroupStats createFileGroupStats(ClientFileGroup clientFileGroup) { 3983 return DataDownloadFileGroupStats.newBuilder() 3984 .setFileGroupName(clientFileGroup.getGroupName()) 3985 .setOwnerPackage(clientFileGroup.getOwnerPackage()) 3986 .setFileGroupVersionNumber(clientFileGroup.getVersionNumber()) 3987 .setFileCount(clientFileGroup.getFileCount()) 3988 .setVariantId(clientFileGroup.getVariantId()) 3989 .setBuildId(clientFileGroup.getBuildId()) 3990 .build(); 3991 } 3992 createDefaultMobileDataDownload()3993 private MobileDataDownload createDefaultMobileDataDownload() { 3994 return new MobileDataDownloadImpl( 3995 context, 3996 mockEventLogger, 3997 mockMobileDataDownloadManager, 3998 controlExecutor, 3999 ImmutableList.of() /* fileGroupPopulatorList */, 4000 Optional.of(mockTaskScheduler), 4001 fileStorage, 4002 Optional.absent() /* downloadMonitorOptional */, 4003 Optional.of(this.getClass()), // don't need to use the real foreground download service. 4004 flags, 4005 singleFileDownloader, 4006 Optional.absent() /* customFileGroupValidator */, 4007 timeSource); 4008 } 4009 } 4010