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.android.libraries.mobiledatadownload.testing.MddTestDependencies.ExecutorType; 19 import static com.google.common.truth.Truth.assertThat; 20 import static java.util.concurrent.TimeUnit.DAYS; 21 import static java.util.concurrent.TimeUnit.SECONDS; 22 import static org.mockito.Mockito.eq; 23 import static org.mockito.Mockito.times; 24 import static org.mockito.Mockito.verify; 25 26 import android.app.blob.BlobStoreManager; 27 import android.content.Context; 28 import android.net.Uri; 29 import android.util.Log; 30 import androidx.test.core.app.ApplicationProvider; 31 import com.google.android.libraries.mobiledatadownload.downloader.FileDownloader; 32 import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage; 33 import com.google.android.libraries.mobiledatadownload.file.backends.AndroidFileBackend; 34 import com.google.android.libraries.mobiledatadownload.file.backends.BlobStoreBackend; 35 import com.google.android.libraries.mobiledatadownload.file.backends.BlobUri; 36 import com.google.android.libraries.mobiledatadownload.file.backends.JavaFileBackend; 37 import com.google.android.libraries.mobiledatadownload.file.transforms.CompressTransform; 38 import com.google.android.libraries.mobiledatadownload.internal.MddTestUtil; 39 import com.google.android.libraries.mobiledatadownload.monitor.DownloadProgressMonitor; 40 import com.google.android.libraries.mobiledatadownload.monitor.NetworkUsageMonitor; 41 import com.google.android.libraries.mobiledatadownload.testing.TestFileDownloader; 42 import com.google.android.libraries.mobiledatadownload.testing.TestFlags; 43 import com.google.common.base.Optional; 44 import com.google.common.base.Supplier; 45 import com.google.common.collect.ImmutableList; 46 import com.google.common.util.concurrent.ListeningExecutorService; 47 import com.google.common.util.concurrent.MoreExecutors; 48 import com.google.mobiledatadownload.ClientConfigProto.ClientFile; 49 import com.google.mobiledatadownload.ClientConfigProto.ClientFileGroup; 50 import com.google.mobiledatadownload.DownloadConfigProto.DataFileGroup; 51 import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions.DeviceNetworkPolicy; 52 import com.google.mobiledatadownload.LogProto.DataDownloadFileGroupStats; 53 import com.google.mobiledatadownload.LogProto.MddLogData; 54 import com.google.testing.junit.testparameterinjector.TestParameter; 55 import com.google.testing.junit.testparameterinjector.TestParameterInjector; 56 import java.util.List; 57 import java.util.concurrent.Executors; 58 import java.util.concurrent.ScheduledExecutorService; 59 import org.junit.After; 60 import org.junit.Before; 61 import org.junit.Rule; 62 import org.junit.Test; 63 import org.junit.runner.RunWith; 64 import org.mockito.ArgumentCaptor; 65 import org.mockito.Mock; 66 import org.mockito.junit.MockitoJUnit; 67 import org.mockito.junit.MockitoRule; 68 69 @RunWith(TestParameterInjector.class) 70 public final class MddGarbageCollectionWithAndroidSharingIntegrationTest { 71 private static final String TAG = "MddGarbageCollectionWithAndroidSharingIntegrationTest"; 72 private static final int MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS = 300; 73 74 private static final String TEST_DATA_RELATIVE_PATH = 75 "third_party/java_src/android_libs/mobiledatadownload/javatests/com/google/android/libraries/mobiledatadownload/testdata/"; 76 77 private static final ScheduledExecutorService DOWNLOAD_EXECUTOR = 78 Executors.newScheduledThreadPool(2); 79 80 private static final String FILE_GROUP_TO_SHARE_1 = "test-group-1"; 81 private static final String FILE_ID_1 = "test-file-to-share-1"; 82 private static final String FILE_CHECKSUM_1 = "fcc96b272633cdf6c4bbd2d77512cca51bfb1dbd"; // SHA_1 83 static final String FILE_ANDROID_SHARING_CHECKSUM_1 = 84 "225017b5d5ec35732940af813b1ab7be5191e4c52659953e75a1a36a1398c48d"; // SHA_256 85 static final int FILE_SIZE_1 = 57; 86 static final String FILE_URL_1 = "https://www.gstatic.com/icing/idd/sample_group/step1.txt"; 87 88 private static final Context context = ApplicationProvider.getApplicationContext(); 89 90 @Mock private TaskScheduler mockTaskScheduler; 91 @Mock private NetworkUsageMonitor mockNetworkUsageMonitor; 92 @Mock private DownloadProgressMonitor mockDownloadProgressMonitor; 93 @Mock private Logger mockLogger; 94 95 private SynchronousFileStorage fileStorage; 96 97 private BlobStoreManager blobStoreManager; 98 private MobileDataDownload mobileDataDownload; 99 private Supplier<FileDownloader> fileDownloaderSupplier; 100 private ListeningExecutorService controlExecutor; 101 102 private final TestFlags flags = new TestFlags(); 103 104 @Rule(order = 1) 105 public final MockitoRule mocks = MockitoJUnit.rule(); 106 107 @TestParameter ExecutorType controlExecutorType; 108 109 @Before setUp()110 public void setUp() throws Exception { 111 112 // cl/439051122 created a temporary FALSE override targeted to ASGA devices. This test suite 113 // relies on garbage collection being enabled to test the metadata state transistions, but 114 // all_on testing doesn't respect diversion criteria in the launch. 115 // 116 // So we temporarily force it on to bypass the launch so the tests can rely on expected 117 // behavior. 118 // TODO(b/226551373): remove these overrides once AsgaDisableMddLibGcLaunch is turned down 119 flags.mddEnableGarbageCollection = Optional.of(true); 120 121 flags.mddAndroidSharingSampleInterval = Optional.of(1); 122 123 flags.mddDefaultSampleInterval = Optional.of(1); 124 125 BlobStoreBackend blobStoreBackend = new BlobStoreBackend(context); 126 blobStoreManager = (BlobStoreManager) context.getSystemService(Context.BLOB_STORE_SERVICE); 127 128 controlExecutor = controlExecutorType.executor(); 129 130 fileStorage = 131 new SynchronousFileStorage( 132 /* backends= */ ImmutableList.of( 133 AndroidFileBackend.builder(context).build(), 134 blobStoreBackend, 135 new JavaFileBackend()), 136 /* transforms= */ ImmutableList.of(new CompressTransform()), 137 /* monitors= */ ImmutableList.of(mockNetworkUsageMonitor, mockDownloadProgressMonitor)); 138 139 fileDownloaderSupplier = 140 () -> 141 new TestFileDownloader( 142 TEST_DATA_RELATIVE_PATH, 143 fileStorage, 144 MoreExecutors.listeningDecorator(DOWNLOAD_EXECUTOR)); 145 } 146 147 @After tearDown()148 public void tearDown() throws Exception { 149 mobileDataDownload.clear().get(); 150 // Commands to clean up the blob storage. 151 MddTestUtil.runShellCmd("cmd blob_store clear-all-sessions"); 152 MddTestUtil.runShellCmd("cmd blob_store clear-all-blobs"); 153 } 154 downloadFileGroup(DataFileGroup fileGroup)155 private void downloadFileGroup(DataFileGroup fileGroup) throws Exception { 156 assertThat( 157 mobileDataDownload 158 .addFileGroup(AddFileGroupRequest.newBuilder().setDataFileGroup(fileGroup).build()) 159 .get()) 160 .isTrue(); 161 mobileDataDownload 162 .downloadFileGroup( 163 DownloadFileGroupRequest.newBuilder() 164 .setGroupName(fileGroup.getGroupName()) 165 .setListenerOptional( 166 Optional.of( 167 new DownloadListener() { 168 @Override 169 public void onProgress(long currentSize) { 170 Log.i(TAG, "onProgress " + currentSize); 171 } 172 173 @Override 174 public void onComplete(ClientFileGroup clientFileGroup) { 175 Log.i(TAG, "onComplete " + clientFileGroup.getGroupName()); 176 } 177 })) 178 .build()) 179 .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS); 180 } 181 verifyDownloadedGroupIsDownloaded(DataFileGroup fileGroup, int fileCount)182 private ClientFileGroup verifyDownloadedGroupIsDownloaded(DataFileGroup fileGroup, int fileCount) 183 throws Exception { 184 ClientFileGroup clientFileGroup = 185 mobileDataDownload 186 .getFileGroup( 187 GetFileGroupRequest.newBuilder().setGroupName(fileGroup.getGroupName()).build()) 188 .get(); 189 190 assertThat(clientFileGroup).isNotNull(); 191 assertThat(clientFileGroup.getGroupName()).isEqualTo(fileGroup.getGroupName()); 192 assertThat(clientFileGroup.getFileCount()).isEqualTo(fileCount); 193 return clientFileGroup; 194 } 195 196 @Test deletesStaleGroups_staleLifetimeZero()197 public void deletesStaleGroups_staleLifetimeZero() throws Exception { 198 mobileDataDownload = builderForTest().build(); 199 Uri androidUri = 200 BlobUri.builder(context).setBlobParameters(FILE_ANDROID_SHARING_CHECKSUM_1).build(); 201 assertThat(fileStorage.exists(androidUri)).isFalse(); 202 203 // Download file group with stale lifetime 0. 204 DataFileGroup fileGroup = 205 TestFileGroupPopulator.createDataFileGroup( 206 FILE_GROUP_TO_SHARE_1, 207 context.getPackageName(), 208 new String[] {FILE_ID_1}, 209 new int[] {FILE_SIZE_1}, 210 new String[] {FILE_CHECKSUM_1}, 211 new String[] {FILE_ANDROID_SHARING_CHECKSUM_1}, 212 new String[] {FILE_URL_1}, 213 DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK); 214 215 downloadFileGroup(fileGroup); 216 217 ClientFileGroup clientFileGroup = verifyDownloadedGroupIsDownloaded(fileGroup, 1); 218 219 ClientFile clientFile = clientFileGroup.getFileList().get(0); 220 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 221 Uri uri = Uri.parse(clientFile.getFileUri()); 222 223 // The file is now available in the android shared storage. 224 assertThat(uri).isEqualTo(androidUri); 225 assertThat(fileStorage.exists(uri)).isTrue(); 226 assertThat(blobStoreManager.getLeasedBlobs()).hasSize(1); 227 228 // Send an empty group so that the old group is now stale. 229 DataFileGroup emptyFileGroup = 230 TestFileGroupPopulator.createDataFileGroup( 231 FILE_GROUP_TO_SHARE_1, 232 context.getPackageName(), 233 new String[] {}, 234 new int[] {}, 235 new String[] {}, 236 new String[] {}, 237 new String[] {}, 238 DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK); 239 240 downloadFileGroup(emptyFileGroup); 241 242 // Run maintenance taks. 243 mobileDataDownload.maintenance().get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS); 244 245 verifyDownloadedGroupIsDownloaded(emptyFileGroup, 0); 246 247 // Old stale file has been released 248 assertThat(blobStoreManager.getLeasedBlobs()).isEmpty(); 249 250 // Verify logging events. 251 252 ArgumentCaptor<MddLogData> logDataCaptor = ArgumentCaptor.forClass(MddLogData.class); 253 // 1050 is the tag number for MddClientEvent.Code.EVENT_CODE_UNSPECIFIED. 254 verify(mockLogger).log(logDataCaptor.capture(), /* eventCode= */ eq(1050)); 255 List<MddLogData> logData = logDataCaptor.getAllValues(); 256 assertThat(logData).hasSize(1); 257 258 DataDownloadFileGroupStats dataDownloadFileGroupStats = 259 logData.get(0).getDataDownloadFileGroupStats(); 260 DataDownloadFileGroupStats staleGroupExpired = 261 DataDownloadFileGroupStats.newBuilder() 262 .setFileGroupName(fileGroup.getGroupName()) 263 .setFileGroupVersionNumber(fileGroup.getFileGroupVersionNumber()) 264 .setBuildId(0) 265 .setVariantId("") 266 .build(); 267 assertThat(dataDownloadFileGroupStats).isEqualTo(staleGroupExpired); 268 269 logDataCaptor = ArgumentCaptor.forClass(MddLogData.class); 270 // 1084 is the tag number for MddClientEvent.Code.EVENT_CODE_UNSPECIFIED; 271 // Called once for every released lease. 272 verify(mockLogger).log(logDataCaptor.capture(), /* eventCode= */ eq(1084)); 273 274 logDataCaptor = ArgumentCaptor.forClass(MddLogData.class); 275 // 1051 is the tag number for MddClientEvent.Code.EVENT_CODE_UNSPECIFIED. 276 // It's logged once by mobileDataDownload.maintenance() and three times in the 277 // ExpirationHandler, once when the file metadata is deleted, once when the lease is released 278 // and once when the temporary local copy of the shared file is deleted. 279 verify(mockLogger, times(4)).log(logDataCaptor.capture(), /* eventCode= */ eq(1051)); 280 logData = logDataCaptor.getAllValues(); 281 assertThat(logData).hasSize(4); 282 283 Void metadafileDeleted = null; 284 Void fileReleased = null; 285 Void fileDeleted = null; 286 } 287 288 @Test deletesStaleGroups_staleLifetimeTwoDays()289 public void deletesStaleGroups_staleLifetimeTwoDays() throws Exception { 290 mobileDataDownload = builderForTest().build(); 291 Uri androidUri = 292 BlobUri.builder(context).setBlobParameters(FILE_ANDROID_SHARING_CHECKSUM_1).build(); 293 assertThat(fileStorage.exists(androidUri)).isFalse(); 294 295 // Download file group with stale lifetime +2 days. 296 DataFileGroup fileGroup = 297 TestFileGroupPopulator.createDataFileGroup( 298 FILE_GROUP_TO_SHARE_1, 299 context.getPackageName(), 300 new String[] {FILE_ID_1}, 301 new int[] {FILE_SIZE_1}, 302 new String[] {FILE_CHECKSUM_1}, 303 new String[] {FILE_ANDROID_SHARING_CHECKSUM_1}, 304 new String[] {FILE_URL_1}, 305 DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK); 306 fileGroup = fileGroup.toBuilder().setStaleLifetimeSecs(DAYS.toSeconds(2)).build(); 307 308 downloadFileGroup(fileGroup); 309 310 ClientFileGroup clientFileGroup = verifyDownloadedGroupIsDownloaded(fileGroup, 1); 311 312 ClientFile clientFile = clientFileGroup.getFileList().get(0); 313 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 314 Uri uri = Uri.parse(clientFile.getFileUri()); 315 316 // The file is now available in the android shared storage. 317 assertThat(uri).isEqualTo(androidUri); 318 assertThat(fileStorage.exists(uri)).isTrue(); 319 assertThat(blobStoreManager.getLeasedBlobs()).hasSize(1); 320 321 // Send an empty group so that the old group is now stale. 322 DataFileGroup emptyFileGroup = 323 TestFileGroupPopulator.createDataFileGroup( 324 FILE_GROUP_TO_SHARE_1, 325 context.getPackageName(), 326 new String[] {}, 327 new int[] {}, 328 new String[] {}, 329 new String[] {}, 330 new String[] {}, 331 DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK); 332 downloadFileGroup(emptyFileGroup); 333 334 // Run maintenance taks. 335 mobileDataDownload.maintenance().get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS); 336 337 verifyDownloadedGroupIsDownloaded(emptyFileGroup, 0); 338 339 // Old stale file hasn't been released yet 340 assertThat(blobStoreManager.getLeasedBlobs()).hasSize(1); 341 342 // Advance time by 2 days, and verify that the lease on the shared file has been 343 // released. 344 MddTestUtil.timeTravel(context, DAYS.toMillis(2)); 345 mobileDataDownload.maintenance().get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS); 346 347 verifyDownloadedGroupIsDownloaded(emptyFileGroup, 0); 348 349 assertThat(blobStoreManager.getLeasedBlobs()).isEmpty(); 350 351 // Verify logging events. 352 353 ArgumentCaptor<MddLogData> logDataCaptor = ArgumentCaptor.forClass(MddLogData.class); 354 // 1050 is the tag number for MddClientEvent.Code.EVENT_CODE_UNSPECIFIED. 355 verify(mockLogger).log(logDataCaptor.capture(), /* eventCode= */ eq(1050)); 356 List<MddLogData> logData = logDataCaptor.getAllValues(); 357 assertThat(logData).hasSize(1); 358 359 DataDownloadFileGroupStats dataDownloadFileGroupStats = 360 logData.get(0).getDataDownloadFileGroupStats(); 361 DataDownloadFileGroupStats staleGroupExpired = 362 DataDownloadFileGroupStats.newBuilder() 363 .setFileGroupName(fileGroup.getGroupName()) 364 .setFileGroupVersionNumber(fileGroup.getFileGroupVersionNumber()) 365 .setBuildId(0) 366 .setVariantId("") 367 .build(); 368 assertThat(dataDownloadFileGroupStats).isEqualTo(staleGroupExpired); 369 370 logDataCaptor = ArgumentCaptor.forClass(MddLogData.class); 371 // 1084 is the tag number for MddClientEvent.Code.EVENT_CODE_UNSPECIFIED; 372 // Called once for every released lease. 373 verify(mockLogger).log(logDataCaptor.capture(), /* eventCode= */ eq(1084)); 374 375 logDataCaptor = ArgumentCaptor.forClass(MddLogData.class); 376 // 1051 is the tag number for MddClientEvent.Code.EVENT_CODE_UNSPECIFIED. 377 // It's logged once every time mobileDataDownload.maintenance() is called and three times in the 378 // ExpirationHandler, once when the file metadata is deleted, once when the lease is released 379 // and once when the temporary local copy of the shared file is deleted. 380 verify(mockLogger, times(5)).log(logDataCaptor.capture(), /* eventCode= */ eq(1051)); 381 logData = logDataCaptor.getAllValues(); 382 assertThat(logData).hasSize(5); 383 384 Void metadafileDeleted = null; 385 Void fileReleased = null; 386 Void fileDeleted = null; 387 } 388 389 @Test deletesExpiredGroups()390 public void deletesExpiredGroups() throws Exception { 391 mobileDataDownload = builderForTest().build(); 392 Uri androidUri = 393 BlobUri.builder(context).setBlobParameters(FILE_ANDROID_SHARING_CHECKSUM_1).build(); 394 assertThat(fileStorage.exists(androidUri)).isFalse(); 395 396 // Download file group with stale lifetime +2 days. 397 DataFileGroup fileGroup = 398 TestFileGroupPopulator.createDataFileGroup( 399 FILE_GROUP_TO_SHARE_1, 400 context.getPackageName(), 401 new String[] {FILE_ID_1}, 402 new int[] {FILE_SIZE_1}, 403 new String[] {FILE_CHECKSUM_1}, 404 new String[] {FILE_ANDROID_SHARING_CHECKSUM_1}, 405 new String[] {FILE_URL_1}, 406 DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK); 407 408 // It expires in two days. 409 fileGroup = fileGroup.toBuilder().setExpirationDate(MddTestUtil.daysFromNow(2)).build(); 410 411 downloadFileGroup(fileGroup); 412 413 ClientFileGroup clientFileGroup = verifyDownloadedGroupIsDownloaded(fileGroup, 1); 414 415 ClientFile clientFile = clientFileGroup.getFileList().get(0); 416 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 417 Uri uri = Uri.parse(clientFile.getFileUri()); 418 419 // The file is now available in the android shared storage. 420 assertThat(uri).isEqualTo(androidUri); 421 assertThat(fileStorage.exists(uri)).isTrue(); 422 assertThat(blobStoreManager.getLeasedBlobs()).hasSize(1); 423 424 // Run maintenance tasks and verify that we still own the lease om the shared file. 425 mobileDataDownload.maintenance().get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS); 426 427 verifyDownloadedGroupIsDownloaded(fileGroup, 1); 428 429 assertThat(blobStoreManager.getLeasedBlobs()).hasSize(1); 430 431 // Advance time by 3 days, and verify that the group and files can no longer be read 432 // because they expired. 433 MddTestUtil.timeTravel(context, DAYS.toMillis(3)); 434 mobileDataDownload.maintenance().get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS); 435 clientFileGroup = 436 mobileDataDownload 437 .getFileGroup( 438 GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_TO_SHARE_1).build()) 439 .get(); 440 assertThat(clientFileGroup).isNull(); 441 442 assertThat(blobStoreManager.getLeasedBlobs()).isEmpty(); 443 444 // Verify logging events. 445 446 ArgumentCaptor<MddLogData> logDataCaptor = ArgumentCaptor.forClass(MddLogData.class); 447 // 1049 is the tag number for MddClientEvent.Code.EVENT_CODE_UNSPECIFIED. 448 verify(mockLogger).log(logDataCaptor.capture(), /* eventCode= */ eq(1049)); 449 450 List<MddLogData> logData = logDataCaptor.getAllValues(); 451 assertThat(logData).hasSize(1); 452 453 DataDownloadFileGroupStats dataDownloadFileGroupStats = 454 logData.get(0).getDataDownloadFileGroupStats(); 455 DataDownloadFileGroupStats groupExpired = 456 DataDownloadFileGroupStats.newBuilder() 457 .setFileGroupName(fileGroup.getGroupName()) 458 .setFileGroupVersionNumber(fileGroup.getFileGroupVersionNumber()) 459 .setBuildId(0) 460 .setVariantId("") 461 .build(); 462 assertThat(dataDownloadFileGroupStats).isEqualTo(groupExpired); 463 464 logDataCaptor = ArgumentCaptor.forClass(MddLogData.class); 465 // 1084 is the tag number for MddClientEvent.Code.EVENT_CODE_UNSPECIFIED; 466 // Called once for every released lease. 467 verify(mockLogger).log(logDataCaptor.capture(), /* eventCode= */ eq(1084)); 468 469 logDataCaptor = ArgumentCaptor.forClass(MddLogData.class); 470 // 1051 is the tag number for MddClientEvent.Code.EVENT_CODE_UNSPECIFIED. 471 // It's logged once every time mobileDataDownload.maintenance() is called and three times in the 472 // ExpirationHandler, once when the file metadata is deleted, once when the lease is 473 // released and once when the temporary local copy of the shared file is deleted. 474 verify(mockLogger, times(5)).log(logDataCaptor.capture(), /* eventCode= */ eq(1051)); 475 logData = logDataCaptor.getAllValues(); 476 assertThat(logData).hasSize(5); 477 478 Void metadafileDeleted = null; 479 Void fileReleased = null; 480 Void fileDeleted = null; 481 } 482 483 /** 484 * Returns MDD Builder with common dependencies set -- additional dependencies are added in each 485 * test as needed. 486 */ builderForTest()487 private MobileDataDownloadBuilder builderForTest() { 488 return MobileDataDownloadBuilder.newBuilder() 489 .setContext(context) 490 .setControlExecutor(controlExecutor) 491 .setFileDownloaderSupplier(fileDownloaderSupplier) 492 .setTaskScheduler(Optional.of(mockTaskScheduler)) 493 .setDeltaDecoderOptional(Optional.absent()) 494 .setFileStorage(fileStorage) 495 .setNetworkUsageMonitor(mockNetworkUsageMonitor) 496 .setDownloadMonitorOptional(Optional.of(mockDownloadProgressMonitor)) 497 .setLoggerOptional(Optional.of(mockLogger)) 498 .setFlagsOptional(Optional.of(flags)); 499 } 500 } 501