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.TestFileGroupPopulator.FILE_CHECKSUM; 19 import static com.google.android.libraries.mobiledatadownload.TestFileGroupPopulator.FILE_ID; 20 import static com.google.android.libraries.mobiledatadownload.TestFileGroupPopulator.FILE_SIZE; 21 import static com.google.android.libraries.mobiledatadownload.TestFileGroupPopulator.FILE_URL; 22 import static com.google.android.libraries.mobiledatadownload.testing.MddTestDependencies.ExecutorType; 23 import static com.google.common.truth.Truth.assertThat; 24 import static java.util.concurrent.TimeUnit.SECONDS; 25 import static org.mockito.Mockito.eq; 26 import static org.mockito.Mockito.times; 27 import static org.mockito.Mockito.verify; 28 29 import android.app.blob.BlobStoreManager; 30 import android.content.Context; 31 import android.net.Uri; 32 import android.util.Log; 33 import androidx.test.core.app.ApplicationProvider; 34 import com.google.android.libraries.mobiledatadownload.downloader.FileDownloader; 35 import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage; 36 import com.google.android.libraries.mobiledatadownload.file.backends.AndroidFileBackend; 37 import com.google.android.libraries.mobiledatadownload.file.backends.BlobStoreBackend; 38 import com.google.android.libraries.mobiledatadownload.file.backends.BlobUri; 39 import com.google.android.libraries.mobiledatadownload.file.backends.JavaFileBackend; 40 import com.google.android.libraries.mobiledatadownload.file.transforms.CompressTransform; 41 import com.google.android.libraries.mobiledatadownload.monitor.DownloadProgressMonitor; 42 import com.google.android.libraries.mobiledatadownload.monitor.NetworkUsageMonitor; 43 import com.google.android.libraries.mobiledatadownload.testing.TestFileDownloader; 44 import com.google.android.libraries.mobiledatadownload.testing.TestFlags; 45 import com.google.common.base.Optional; 46 import com.google.common.base.Supplier; 47 import com.google.common.collect.ImmutableList; 48 import com.google.common.io.BaseEncoding; 49 import com.google.common.util.concurrent.ListeningExecutorService; 50 import com.google.common.util.concurrent.MoreExecutors; 51 import com.google.mobiledatadownload.ClientConfigProto.ClientFile; 52 import com.google.mobiledatadownload.ClientConfigProto.ClientFileGroup; 53 import com.google.mobiledatadownload.DownloadConfigProto.DataFileGroup; 54 import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions.DeviceNetworkPolicy; 55 import com.google.mobiledatadownload.LogProto.MddLogData; 56 import com.google.testing.junit.testparameterinjector.TestParameter; 57 import com.google.testing.junit.testparameterinjector.TestParameterInjector; 58 import java.io.OutputStream; 59 import java.security.MessageDigest; 60 import java.util.Calendar; 61 import java.util.List; 62 import java.util.concurrent.Executors; 63 import java.util.concurrent.ScheduledExecutorService; 64 import org.junit.After; 65 import org.junit.Before; 66 import org.junit.Rule; 67 import org.junit.Test; 68 import org.junit.runner.RunWith; 69 import org.mockito.ArgumentCaptor; 70 import org.mockito.Mock; 71 import org.mockito.junit.MockitoJUnit; 72 import org.mockito.junit.MockitoRule; 73 74 @RunWith(TestParameterInjector.class) 75 public class DownloadFileGroupAndroidSharingIntegrationTest { 76 77 private static final String TAG = "DownloadFileGroupIntegrationTest"; 78 private static final int MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS = 300; 79 80 private static final String TEST_DATA_RELATIVE_PATH = 81 "third_party/java_src/android_libs/mobiledatadownload/javatests/com/google/android/libraries/mobiledatadownload/testdata/"; 82 83 private static final ScheduledExecutorService DOWNLOAD_EXECUTOR = 84 Executors.newScheduledThreadPool(2); 85 86 private static final String FILE_GROUP_TO_SHARE_1 = "test-group-1"; 87 private static final String FILE_GROUP_TO_SHARE_2 = "test-group-2"; 88 89 private static final String FILE_ID_1 = "test-file-to-share-1"; 90 private static final String FILE_CHECKSUM_1 = "fcc96b272633cdf6c4bbd2d77512cca51bfb1dbd"; // SHA_1 91 static final String FILE_ANDROID_SHARING_CHECKSUM_1 = 92 "225017b5d5ec35732940af813b1ab7be5191e4c52659953e75a1a36a1398c48d"; // SHA_256 93 static final int FILE_SIZE_1 = 57; 94 static final String FILE_URL_1 = "https://www.gstatic.com/icing/idd/sample_group/step1.txt"; 95 96 private static final String FILE_ID_2 = "test-file-to-share-2"; 97 private static final String FILE_CHECKSUM_2 = "22d565c9511c5752baab8a3bbf7b955bd2ca66fd"; // SHA_1 98 static final String FILE_ANDROID_SHARING_CHECKSUM_2 = 99 "98863d56d683f6f1fdf17b38873a481f47a3216e05314750f9b384220af418ab"; // SHA_256 100 static final int FILE_SIZE_2 = 13; 101 static final String FILE_URL_2 = "https://www.gstatic.com/icing/idd/sample_group/step2.txt"; 102 103 private static final Context context = ApplicationProvider.getApplicationContext(); 104 105 @Mock private TaskScheduler mockTaskScheduler; 106 @Mock private NetworkUsageMonitor mockNetworkUsageMonitor; 107 @Mock private DownloadProgressMonitor mockDownloadProgressMonitor; 108 @Mock private Logger mockLogger; 109 110 private SynchronousFileStorage fileStorage; 111 private BlobStoreBackend blobStoreBackend; 112 private BlobStoreManager blobStoreManager; 113 private MobileDataDownload mobileDataDownload; 114 private ListeningExecutorService controlExecutor; 115 116 private final TestFlags flags = new TestFlags(); 117 118 @Rule public final MockitoRule mocks = MockitoJUnit.rule(); 119 120 // TODO(b/226405643): Some tests seem to fail due to BlobStore not clearing out files across runs. 121 // Investigate why this is happening and enable single-threaded tests. 122 @TestParameter({"MULTI_THREADED"}) 123 ExecutorType controlExecutorType; 124 125 @Before setUp()126 public void setUp() throws Exception { 127 128 flags.mddAndroidSharingSampleInterval = Optional.of(1); 129 130 flags.mddDefaultSampleInterval = Optional.of(1); 131 132 blobStoreBackend = new BlobStoreBackend(context); 133 blobStoreManager = (BlobStoreManager) context.getSystemService(Context.BLOB_STORE_SERVICE); 134 135 fileStorage = 136 new SynchronousFileStorage( 137 /* backends= */ ImmutableList.of( 138 AndroidFileBackend.builder(context).build(), 139 blobStoreBackend, 140 new JavaFileBackend()), 141 /* transforms= */ ImmutableList.of(new CompressTransform()), 142 /* monitors= */ ImmutableList.of(mockNetworkUsageMonitor, mockDownloadProgressMonitor)); 143 144 controlExecutor = controlExecutorType.executor(); 145 } 146 147 @After tearDown()148 public void tearDown() throws Exception { 149 mobileDataDownload.clear().get(); 150 } 151 computeDigest(byte[] byteContent, String algorithm)152 private static String computeDigest(byte[] byteContent, String algorithm) throws Exception { 153 MessageDigest messageDigest = MessageDigest.getInstance(algorithm); 154 if (messageDigest == null) { 155 return ""; 156 } 157 return BaseEncoding.base16().lowerCase().encode(messageDigest.digest(byteContent)); 158 } 159 160 @Test oneAndroidSharedFile_blobStoreBackendNotRegistered_fileDownloadedAndStoredLocally()161 public void oneAndroidSharedFile_blobStoreBackendNotRegistered_fileDownloadedAndStoredLocally() 162 throws Exception { 163 fileStorage = 164 new SynchronousFileStorage( 165 /* backends= */ ImmutableList.of( 166 AndroidFileBackend.builder(context).build(), new JavaFileBackend()), 167 /* transforms= */ ImmutableList.of(new CompressTransform()), 168 /* monitors= */ ImmutableList.of(mockNetworkUsageMonitor, mockDownloadProgressMonitor)); 169 170 mobileDataDownload = builderForTest().setFileStorage(fileStorage).build(); 171 172 Uri androidUri = 173 BlobUri.builder(context).setBlobParameters(FILE_ANDROID_SHARING_CHECKSUM_1).build(); 174 175 // A file group with one android-shared file and one non-androidShared file 176 DataFileGroup groupWithFileToShare = 177 TestFileGroupPopulator.createDataFileGroup( 178 FILE_GROUP_TO_SHARE_1, 179 context.getPackageName(), 180 new String[] {FILE_ID_1, FILE_ID}, 181 new int[] {FILE_SIZE_1, FILE_SIZE}, 182 new String[] {FILE_CHECKSUM_1, FILE_CHECKSUM}, 183 new String[] {FILE_ANDROID_SHARING_CHECKSUM_1, ""}, 184 new String[] {FILE_URL_1, FILE_URL}, 185 DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK); 186 187 assertThat( 188 mobileDataDownload 189 .addFileGroup( 190 AddFileGroupRequest.newBuilder().setDataFileGroup(groupWithFileToShare).build()) 191 .get()) 192 .isTrue(); 193 194 mobileDataDownload 195 .downloadFileGroup( 196 DownloadFileGroupRequest.newBuilder() 197 .setGroupName(FILE_GROUP_TO_SHARE_1) 198 .setListenerOptional( 199 Optional.of( 200 new DownloadListener() { 201 @Override 202 public void onProgress(long currentSize) { 203 Log.i(TAG, "onProgress " + currentSize); 204 } 205 206 @Override 207 public void onComplete(ClientFileGroup clientFileGroup) { 208 Log.i(TAG, "onComplete " + clientFileGroup.getGroupName()); 209 } 210 })) 211 .build()) 212 .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS); 213 214 ClientFileGroup clientFileGroup = 215 mobileDataDownload 216 .getFileGroup( 217 GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_TO_SHARE_1).build()) 218 .get(); 219 220 assertThat(clientFileGroup).isNotNull(); 221 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_TO_SHARE_1); 222 assertThat(clientFileGroup.getFileCount()).isEqualTo(2); 223 224 ClientFile clientFile = clientFileGroup.getFileList().get(0); 225 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 226 Uri uri = Uri.parse(clientFile.getFileUri()); 227 assertThat(uri).isNotEqualTo(androidUri); 228 assertThat(fileStorage.fileSize(uri)).isEqualTo(FILE_SIZE_1); 229 230 clientFile = clientFileGroup.getFileList().get(1); 231 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID); 232 uri = Uri.parse(clientFile.getFileUri()); 233 assertThat(fileStorage.fileSize(uri)).isEqualTo(FILE_SIZE); 234 235 ArgumentCaptor<MddLogData> logDataCaptor = ArgumentCaptor.forClass(MddLogData.class); 236 // 1073 is the tag number for MddClientEvent.Code.EVENT_CODE_UNSPECIFIED. 237 verify(mockLogger, times(2)).log(logDataCaptor.capture(), /* eventCode= */ eq(1073)); 238 239 List<MddLogData> logData = logDataCaptor.getAllValues(); 240 Void log1 = null; 241 Void log2 = null; 242 assertThat(logData).hasSize(2); 243 244 Void androidSharingLog = null; 245 assertThat(log1).isEqualTo(androidSharingLog); 246 assertThat(log2).isEqualTo(androidSharingLog); 247 } 248 249 @Test oneAndroidSharedFile_twoFileGroups_downloadedOnlyOnce()250 public void oneAndroidSharedFile_twoFileGroups_downloadedOnlyOnce() throws Exception { 251 mobileDataDownload = builderForTest().build(); 252 253 Uri androidUri = 254 BlobUri.builder(context).setBlobParameters(FILE_ANDROID_SHARING_CHECKSUM_1).build(); 255 assertThat(fileStorage.exists(androidUri)).isFalse(); 256 257 // groupWithFileToShare1 and groupWithFileToShare2 contain the same file configured to be 258 // shared. 259 DataFileGroup groupWithFileToShare1 = 260 TestFileGroupPopulator.createDataFileGroup( 261 FILE_GROUP_TO_SHARE_1, 262 context.getPackageName(), 263 new String[] {FILE_ID_1}, 264 new int[] {FILE_SIZE_1}, 265 new String[] {FILE_CHECKSUM_1}, 266 new String[] {FILE_ANDROID_SHARING_CHECKSUM_1}, 267 new String[] {FILE_URL_1}, 268 DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK); 269 270 long oneDayLaterInSeconds = 271 Calendar.getInstance().getTimeInMillis() / 1000 + 86400; // in one day 272 groupWithFileToShare1 = 273 groupWithFileToShare1.toBuilder().setExpirationDate(oneDayLaterInSeconds).build(); 274 275 DataFileGroup groupWithFileToShare2 = 276 TestFileGroupPopulator.createDataFileGroup( 277 FILE_GROUP_TO_SHARE_2, 278 context.getPackageName(), 279 new String[] {FILE_ID_1}, 280 new int[] {FILE_SIZE_1}, 281 new String[] {FILE_CHECKSUM_1}, 282 new String[] {FILE_ANDROID_SHARING_CHECKSUM_1}, 283 new String[] {FILE_URL_1}, 284 DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK); 285 286 long twoDaysLaterInSeconds = 287 Calendar.getInstance().getTimeInMillis() / 1000 + 172800; // in two days 288 groupWithFileToShare2 = 289 groupWithFileToShare2.toBuilder().setExpirationDate(twoDaysLaterInSeconds).build(); 290 291 assertThat( 292 mobileDataDownload 293 .addFileGroup( 294 AddFileGroupRequest.newBuilder() 295 .setDataFileGroup(groupWithFileToShare1) 296 .build()) 297 .get()) 298 .isTrue(); 299 300 assertThat( 301 mobileDataDownload 302 .addFileGroup( 303 AddFileGroupRequest.newBuilder() 304 .setDataFileGroup(groupWithFileToShare2) 305 .build()) 306 .get()) 307 .isTrue(); 308 309 mobileDataDownload 310 .downloadFileGroup( 311 DownloadFileGroupRequest.newBuilder() 312 .setGroupName(FILE_GROUP_TO_SHARE_1) 313 .setListenerOptional( 314 Optional.of( 315 new DownloadListener() { 316 @Override 317 public void onProgress(long currentSize) { 318 Log.i(TAG, "onProgress " + currentSize); 319 } 320 321 @Override 322 public void onComplete(ClientFileGroup clientFileGroup) { 323 Log.i(TAG, "onComplete " + clientFileGroup.getGroupName()); 324 } 325 })) 326 .build()) 327 .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS); 328 329 ClientFileGroup clientFileGroup = 330 mobileDataDownload 331 .getFileGroup( 332 GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_TO_SHARE_1).build()) 333 .get(); 334 335 assertThat(clientFileGroup).isNotNull(); 336 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_TO_SHARE_1); 337 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 338 339 ClientFile clientFile = clientFileGroup.getFileList().get(0); 340 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 341 Uri uri = Uri.parse(clientFile.getFileUri()); 342 343 // The file is now available in the android shared storage. 344 assertThat(uri).isEqualTo(androidUri); 345 assertThat(fileStorage.exists(uri)).isTrue(); 346 assertThat(blobStoreManager.getLeasedBlobs()).hasSize(1); 347 348 mobileDataDownload 349 .downloadFileGroup( 350 DownloadFileGroupRequest.newBuilder() 351 .setGroupName(FILE_GROUP_TO_SHARE_2) 352 .setListenerOptional( 353 Optional.of( 354 new DownloadListener() { 355 @Override 356 public void onProgress(long currentSize) { 357 Log.i(TAG, "onProgress " + currentSize); 358 } 359 360 @Override 361 public void onComplete(ClientFileGroup clientFileGroup) { 362 Log.i(TAG, "onComplete " + clientFileGroup.getGroupName()); 363 } 364 })) 365 .build()) 366 .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS); 367 368 String debugString = mobileDataDownload.getDebugInfoAsString(); 369 Log.i(TAG, "MDD Lib dump:"); 370 for (String line : debugString.split("\n", -1)) { 371 Log.i(TAG, line); 372 } 373 374 clientFileGroup = 375 mobileDataDownload 376 .getFileGroup( 377 GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_TO_SHARE_2).build()) 378 .get(); 379 380 assertThat(clientFileGroup).isNotNull(); 381 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_TO_SHARE_2); 382 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 383 384 clientFile = clientFileGroup.getFileList().get(0); 385 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 386 uri = Uri.parse(clientFile.getFileUri()); 387 388 // The file is still available in the android shared storage. 389 assertThat(uri).isEqualTo(androidUri); 390 assertThat(fileStorage.exists(uri)).isTrue(); 391 assertThat(blobStoreManager.getLeasedBlobs()).hasSize(1); 392 393 ArgumentCaptor<MddLogData> logDataCaptor = ArgumentCaptor.forClass(MddLogData.class); 394 // 1073 is the tag number for MddClientEvent.Code.EVENT_CODE_UNSPECIFIED. 395 verify(mockLogger, times(2)).log(logDataCaptor.capture(), /* eventCode= */ eq(1073)); 396 397 List<MddLogData> logData = logDataCaptor.getAllValues(); 398 assertThat(logData).hasSize(2); 399 400 Void log1 = null; 401 Void log2 = null; 402 } 403 404 @Test fileAvailableInSharedStorage_neverDownloaded()405 public void fileAvailableInSharedStorage_neverDownloaded() throws Exception { 406 mobileDataDownload = builderForTest().build(); 407 408 byte[] content = "fileAvailableInSharedStorage_neverDownloaded".getBytes(); 409 String androidChecksum = computeDigest(content, "SHA-256"); 410 String checksum = computeDigest(content, "SHA-1"); 411 Uri androidUri = BlobUri.builder(context).setBlobParameters(androidChecksum).build(); 412 413 assertThat(blobStoreBackend.exists(androidUri)).isFalse(); 414 415 // Write file in the shared storage 416 try (OutputStream out = blobStoreBackend.openForWrite(androidUri)) { 417 assertThat(out).isNotNull(); 418 out.write(content); 419 } 420 assertThat(blobStoreBackend.exists(androidUri)).isTrue(); 421 assertThat(blobStoreManager.getLeasedBlobs()).isEmpty(); 422 423 // A file group with one android-shared file and one non-androidShared file 424 DataFileGroup groupWithFileToShare1 = 425 TestFileGroupPopulator.createDataFileGroup( 426 FILE_GROUP_TO_SHARE_1, 427 context.getPackageName(), 428 new String[] {FILE_ID_1, FILE_ID}, 429 new int[] {content.length, FILE_SIZE}, 430 new String[] {checksum, FILE_CHECKSUM}, 431 new String[] {androidChecksum, ""}, 432 new String[] {"https://random-url", FILE_URL}, 433 DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK); 434 435 assertThat( 436 mobileDataDownload 437 .addFileGroup( 438 AddFileGroupRequest.newBuilder() 439 .setDataFileGroup(groupWithFileToShare1) 440 .build()) 441 .get()) 442 .isTrue(); 443 444 mobileDataDownload 445 .downloadFileGroup( 446 DownloadFileGroupRequest.newBuilder() 447 .setGroupName(FILE_GROUP_TO_SHARE_1) 448 .setListenerOptional( 449 Optional.of( 450 new DownloadListener() { 451 @Override 452 public void onProgress(long currentSize) { 453 Log.i(TAG, "onProgress " + currentSize); 454 } 455 456 @Override 457 public void onComplete(ClientFileGroup clientFileGroup) { 458 Log.i(TAG, "onComplete " + clientFileGroup.getGroupName()); 459 } 460 })) 461 .build()) 462 .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS); 463 464 ClientFileGroup clientFileGroup = 465 mobileDataDownload 466 .getFileGroup( 467 GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_TO_SHARE_1).build()) 468 .get(); 469 470 assertThat(clientFileGroup).isNotNull(); 471 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_TO_SHARE_1); 472 assertThat(clientFileGroup.getFileCount()).isEqualTo(2); 473 474 ClientFile clientFile = clientFileGroup.getFileList().get(0); 475 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_1); 476 Uri uri = Uri.parse(clientFile.getFileUri()); 477 478 // The file is available in the android shared storage. 479 assertThat(uri).isEqualTo(androidUri); 480 assertThat(fileStorage.exists(androidUri)).isTrue(); 481 assertThat(blobStoreManager.getLeasedBlobs()).hasSize(1); 482 483 clientFile = clientFileGroup.getFileList().get(1); 484 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID); 485 uri = Uri.parse(clientFile.getFileUri()); 486 assertThat(fileStorage.fileSize(uri)).isEqualTo(FILE_SIZE); 487 488 ArgumentCaptor<MddLogData> logDataCaptor = ArgumentCaptor.forClass(MddLogData.class); 489 // 1073 is the tag number for MddClientEvent.Code.EVENT_CODE_UNSPECIFIED. 490 verify(mockLogger).log(logDataCaptor.capture(), /* eventCode= */ eq(1073)); 491 492 List<MddLogData> logData = logDataCaptor.getAllValues(); 493 assertThat(logData).hasSize(1); 494 495 Void log1 = null; 496 } 497 498 @Test fileDownloadedForFirstFileGroup_thenSharedForSecondFileGroup()499 public void fileDownloadedForFirstFileGroup_thenSharedForSecondFileGroup() throws Exception { 500 mobileDataDownload = builderForTest().build(); 501 502 Uri androidUri = 503 BlobUri.builder(context).setBlobParameters(FILE_ANDROID_SHARING_CHECKSUM_2).build(); 504 assertThat(blobStoreBackend.exists(androidUri)).isFalse(); 505 506 // Create non-android-shared file group. 507 DataFileGroup groupWithFileToShare1 = 508 TestFileGroupPopulator.createDataFileGroup( 509 FILE_GROUP_TO_SHARE_1, 510 context.getPackageName(), 511 new String[] {FILE_ID_2}, 512 new int[] {FILE_SIZE_2}, 513 new String[] {FILE_CHECKSUM_2}, 514 new String[] {FILE_URL_2}, 515 DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK); 516 517 long laterTimeSecs = Calendar.getInstance().getTimeInMillis() / 1000 + 86400; // in one day 518 groupWithFileToShare1 = 519 groupWithFileToShare1.toBuilder().setExpirationDate(laterTimeSecs).build(); 520 521 assertThat( 522 mobileDataDownload 523 .addFileGroup( 524 AddFileGroupRequest.newBuilder() 525 .setDataFileGroup(groupWithFileToShare1) 526 .build()) 527 .get()) 528 .isTrue(); 529 530 // groupWithFileToShare2 has the same file as the previous file group but it has been configured 531 // to be share. 532 DataFileGroup groupWithFileToShare2 = 533 TestFileGroupPopulator.createDataFileGroup( 534 FILE_GROUP_TO_SHARE_2, 535 context.getPackageName(), 536 new String[] {FILE_ID_2}, 537 new int[] {FILE_SIZE_2}, 538 new String[] {FILE_CHECKSUM_2}, 539 new String[] {FILE_ANDROID_SHARING_CHECKSUM_2}, 540 new String[] {FILE_URL_2}, 541 DeviceNetworkPolicy.DOWNLOAD_ON_ANY_NETWORK); 542 543 assertThat( 544 mobileDataDownload 545 .addFileGroup( 546 AddFileGroupRequest.newBuilder() 547 .setDataFileGroup(groupWithFileToShare2) 548 .build()) 549 .get()) 550 .isTrue(); 551 552 mobileDataDownload 553 .downloadFileGroup( 554 DownloadFileGroupRequest.newBuilder() 555 .setGroupName(FILE_GROUP_TO_SHARE_1) 556 .setListenerOptional( 557 Optional.of( 558 new DownloadListener() { 559 @Override 560 public void onProgress(long currentSize) { 561 Log.i(TAG, "onProgress " + currentSize); 562 } 563 564 @Override 565 public void onComplete(ClientFileGroup clientFileGroup) { 566 Log.i(TAG, "onComplete " + clientFileGroup.getGroupName()); 567 } 568 })) 569 .build()) 570 .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS); 571 572 ClientFileGroup clientFileGroup = 573 mobileDataDownload 574 .getFileGroup( 575 GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_TO_SHARE_1).build()) 576 .get(); 577 578 assertThat(clientFileGroup).isNotNull(); 579 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_TO_SHARE_1); 580 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 581 582 ClientFile clientFile = clientFileGroup.getFileList().get(0); 583 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_2); 584 585 // File stored locally 586 Uri localUri = Uri.parse(clientFile.getFileUri()); 587 assertThat(localUri).isNotEqualTo(androidUri); 588 assertThat(blobStoreManager.getLeasedBlobs()).isEmpty(); 589 590 mobileDataDownload 591 .downloadFileGroup( 592 DownloadFileGroupRequest.newBuilder() 593 .setGroupName(FILE_GROUP_TO_SHARE_2) 594 .setListenerOptional( 595 Optional.of( 596 new DownloadListener() { 597 @Override 598 public void onProgress(long currentSize) { 599 Log.i(TAG, "onProgress " + currentSize); 600 } 601 602 @Override 603 public void onComplete(ClientFileGroup clientFileGroup) { 604 Log.i(TAG, "onComplete " + clientFileGroup.getGroupName()); 605 } 606 })) 607 .build()) 608 .get(MAX_DOWNLOAD_FILE_GROUP_WAIT_TIME_SECS, SECONDS); 609 610 String debugString = mobileDataDownload.getDebugInfoAsString(); 611 Log.i(TAG, "MDD Lib dump:"); 612 for (String line : debugString.split("\n", -1)) { 613 Log.i(TAG, line); 614 } 615 616 clientFileGroup = 617 mobileDataDownload 618 .getFileGroup( 619 GetFileGroupRequest.newBuilder().setGroupName(FILE_GROUP_TO_SHARE_2).build()) 620 .get(); 621 622 assertThat(clientFileGroup).isNotNull(); 623 assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_TO_SHARE_2); 624 assertThat(clientFileGroup.getFileCount()).isEqualTo(1); 625 626 clientFile = clientFileGroup.getFileList().get(0); 627 assertThat(clientFile.getFileId()).isEqualTo(FILE_ID_2); 628 Uri uri = Uri.parse(clientFile.getFileUri()); 629 630 // The file is now available in the shared storage. 631 assertThat(uri).isNotEqualTo(localUri); 632 assertThat(uri).isEqualTo(androidUri); 633 assertThat(fileStorage.exists(uri)).isTrue(); 634 assertThat(blobStoreManager.getLeasedBlobs()).hasSize(1); 635 636 ArgumentCaptor<MddLogData> logDataCaptor = ArgumentCaptor.forClass(MddLogData.class); 637 // 1073 is the tag number for MddClientEvent.Code.EVENT_CODE_UNSPECIFIED. 638 verify(mockLogger).log(logDataCaptor.capture(), /* eventCode= */ eq(1073)); 639 640 List<MddLogData> logData = logDataCaptor.getAllValues(); 641 assertThat(logData).hasSize(1); 642 643 Void log1 = null; 644 } 645 builderForTest()646 private MobileDataDownloadBuilder builderForTest() { 647 Supplier<FileDownloader> fileDownloaderSupplier = 648 () -> 649 new TestFileDownloader( 650 TEST_DATA_RELATIVE_PATH, 651 fileStorage, 652 MoreExecutors.listeningDecorator(DOWNLOAD_EXECUTOR)); 653 654 return MobileDataDownloadBuilder.newBuilder() 655 .setContext(context) 656 .setControlExecutor(controlExecutor) 657 .setFileDownloaderSupplier(fileDownloaderSupplier) 658 .setTaskScheduler(Optional.of(mockTaskScheduler)) 659 .setDeltaDecoderOptional(Optional.absent()) 660 .setFileStorage(fileStorage) 661 .setNetworkUsageMonitor(mockNetworkUsageMonitor) 662 .setDownloadMonitorOptional(Optional.of(mockDownloadProgressMonitor)) 663 .setLoggerOptional(Optional.of(mockLogger)) 664 .setFlagsOptional(Optional.of(flags)); 665 } 666 } 667