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.internal; 17 18 import static com.google.common.truth.Truth.assertThat; 19 20 import android.content.Context; 21 import android.content.SharedPreferences; 22 import android.net.Uri; 23 import androidx.test.core.app.ApplicationProvider; 24 import com.google.mobiledatadownload.internal.MetadataProto.DataFile; 25 import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupInternal.AllowedReaders; 26 import com.google.mobiledatadownload.internal.MetadataProto.FileStatus; 27 import com.google.mobiledatadownload.internal.MetadataProto.NewFileKey; 28 import com.google.mobiledatadownload.internal.MetadataProto.SharedFile; 29 import com.google.android.libraries.mobiledatadownload.SilentFeedback; 30 import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage; 31 import com.google.android.libraries.mobiledatadownload.file.backends.AndroidFileBackend; 32 import com.google.android.libraries.mobiledatadownload.file.backends.AndroidUri; 33 import com.google.android.libraries.mobiledatadownload.internal.Migrations.FileKeyVersion; 34 import com.google.android.libraries.mobiledatadownload.internal.logging.EventLogger; 35 import com.google.android.libraries.mobiledatadownload.internal.util.SharedFilesMetadataUtil; 36 import com.google.android.libraries.mobiledatadownload.internal.util.SharedFilesMetadataUtil.FileKeyDeserializationException; 37 import com.google.android.libraries.mobiledatadownload.internal.util.SharedPreferencesUtil; 38 import com.google.android.libraries.mobiledatadownload.testing.TestFlags; 39 import com.google.common.base.Optional; 40 import com.google.common.util.concurrent.MoreExecutors; 41 import com.google.mobiledatadownload.TransformProto.CompressTransform; 42 import com.google.mobiledatadownload.TransformProto.Transform; 43 import com.google.mobiledatadownload.TransformProto.Transforms; 44 import java.io.IOException; 45 import java.util.Arrays; 46 import java.util.Collection; 47 import java.util.List; 48 import java.util.concurrent.ExecutionException; 49 import java.util.concurrent.Executor; 50 import java.util.concurrent.Executors; 51 import org.junit.After; 52 import org.junit.Before; 53 import org.junit.Rule; 54 import org.junit.Test; 55 import org.junit.runner.RunWith; 56 import org.mockito.Mock; 57 import org.mockito.junit.MockitoJUnit; 58 import org.mockito.junit.MockitoRule; 59 import org.robolectric.ParameterizedRobolectricTestRunner; 60 import org.robolectric.ParameterizedRobolectricTestRunner.Parameter; 61 import org.robolectric.ParameterizedRobolectricTestRunner.Parameters; 62 63 @RunWith(ParameterizedRobolectricTestRunner.class) 64 public class SharedFilesMetadataTest { 65 66 private enum MetadataStoreImpl { 67 SP_IMPL, 68 } 69 70 @Parameters(name = "metadataStoreImpl = {0} instanceId = {1}") parameters()71 public static Collection<Object[]> parameters() { 72 return Arrays.asList( 73 new Object[][] { 74 {MetadataStoreImpl.SP_IMPL, Optional.absent()}, 75 {MetadataStoreImpl.SP_IMPL, Optional.of("id")}, 76 }); 77 } 78 79 @Parameter(value = 0) 80 public MetadataStoreImpl metadataStoreImpl; 81 82 @Parameter(value = 1) 83 public Optional<String> instanceId; 84 85 private SynchronousFileStorage storage; 86 private Context context; 87 private SharedFilesMetadata sharedFilesMetadata; 88 private Uri diagnosticUri; 89 private Uri destinationUri; 90 91 private final TestFlags flags = new TestFlags(); 92 93 @Mock SilentFeedback mockSilentFeedback; 94 @Mock EventLogger mockLogger; 95 96 private static final Transforms COMPRESS_TRANSFORM = 97 Transforms.newBuilder() 98 .addTransform(Transform.newBuilder().setCompress(CompressTransform.getDefaultInstance())) 99 .build(); 100 private static final Executor CONTROL_EXECUTOR = 101 MoreExecutors.newSequentialExecutor(Executors.newCachedThreadPool()); 102 103 @Rule public final MockitoRule mocks = MockitoJUnit.rule(); 104 105 @Before setUp()106 public void setUp() throws InterruptedException, ExecutionException { 107 108 context = ApplicationProvider.getApplicationContext(); 109 110 storage = 111 new SynchronousFileStorage(Arrays.asList(AndroidFileBackend.builder(context).build())); 112 113 destinationUri = 114 AndroidUri.builder(context) 115 .setPackage(context.getPackageName()) 116 .setRelativePath("dest.pb") 117 .build(); 118 diagnosticUri = 119 AndroidUri.builder(context) 120 .setPackage(context.getPackageName()) 121 .setRelativePath("diag.pb") 122 .build(); 123 124 SharedPreferencesSharedFilesMetadata sharedPreferencesMetadata = 125 new SharedPreferencesSharedFilesMetadata(context, mockSilentFeedback, instanceId, flags); 126 127 switch (metadataStoreImpl) { 128 case SP_IMPL: 129 sharedFilesMetadata = sharedPreferencesMetadata; 130 break; 131 } 132 133 Migrations.clear(context); 134 Migrations.setMigratedToNewFileKey(context, true); 135 } 136 137 @After tearDown()138 public void tearDown() throws InterruptedException, ExecutionException, IOException { 139 if (storage.exists(diagnosticUri)) { 140 storage.deleteFile(diagnosticUri); 141 } 142 if (storage.exists(destinationUri)) { 143 storage.deleteFile(destinationUri); 144 } 145 synchronized (SharedPreferencesSharedFilesMetadata.class) { 146 sharedFilesMetadata.clear().get(); 147 assertThat( 148 SharedPreferencesUtil.getSharedPreferences( 149 context, SharedFilesMetadataUtil.MDD_SHARED_FILES, instanceId) 150 .edit() 151 .clear() 152 .commit()) 153 .isTrue(); 154 } 155 } 156 157 @Test init_alwaysMigrateToNewKey()158 public void init_alwaysMigrateToNewKey() throws InterruptedException, ExecutionException { 159 Migrations.setMigratedToNewFileKey(context, false); 160 flags.fileKeyVersion = Optional.of(FileKeyVersion.USE_CHECKSUM_ONLY.value); 161 162 assertThat(sharedFilesMetadata.init().get()).isFalse(); 163 164 assertThat(Migrations.isMigratedToNewFileKey(context)).isTrue(); 165 166 // Verify that we also set the current file version to the latest version in this case. 167 assertThat(Migrations.getCurrentVersion(context, mockSilentFeedback)) 168 .isEqualTo(FileKeyVersion.USE_CHECKSUM_ONLY); 169 } 170 171 @Test testMigrateToNewVersion_noVersionChange()172 public void testMigrateToNewVersion_noVersionChange() 173 throws InterruptedException, ExecutionException { 174 flags.fileKeyVersion = Optional.of(FileKeyVersion.NEW_FILE_KEY.value); 175 176 // Create two files, one downloaded and the other currently being downloaded. 177 DataFile registeredFile = MddTestUtil.createDataFile("registered-file", 0); 178 DataFile downloadedFile = MddTestUtil.createDataFile("downloaded-file", /* fileIndex */ 0); 179 180 NewFileKey downloadedKey = 181 SharedFilesMetadata.createKeyFromDataFile(downloadedFile, AllowedReaders.ALL_GOOGLE_APPS); 182 NewFileKey registeredKey = 183 SharedFilesMetadata.createKeyFromDataFile( 184 registeredFile, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES); 185 186 SharedFile registeredSharedFile = 187 SharedFile.newBuilder() 188 .setFileName("registered-file") 189 .setFileStatus(FileStatus.SUBSCRIBED) 190 .build(); 191 SharedFile downloadedSharedFile = 192 SharedFile.newBuilder() 193 .setFileName("downloaded-file") 194 .setFileStatus(FileStatus.DOWNLOAD_COMPLETE) 195 .build(); 196 197 synchronized (SharedPreferencesSharedFilesMetadata.class) { 198 assertThat(writeSharedFile(registeredKey, registeredSharedFile)).isTrue(); 199 assertThat(writeSharedFile(downloadedKey, downloadedSharedFile)).isTrue(); 200 } 201 202 assertThat(sharedFilesMetadata.init().get()).isTrue(); 203 204 // Check that we are able to read the file after the migration. 205 assertThat(sharedFilesMetadata.read(registeredKey).get()).isEqualTo(registeredSharedFile); 206 assertThat(sharedFilesMetadata.read(downloadedKey).get()).isEqualTo(downloadedSharedFile); 207 208 verifyNoErrorInPdsMigration(); 209 } 210 211 @Test testMigrateToNewVersion_toAddDownloadTransform()212 public void testMigrateToNewVersion_toAddDownloadTransform() 213 throws InterruptedException, ExecutionException { 214 flags.fileKeyVersion = Optional.of(FileKeyVersion.ADD_DOWNLOAD_TRANSFORM.value); 215 216 // Create two files, one downloaded and the other currently being downloaded. 217 DataFile registeredFile = MddTestUtil.createDataFile("registered-file", 0); 218 DataFile downloadedFile = MddTestUtil.createDataFile("downloaded-file", /* fileIndex */ 0); 219 220 NewFileKey downloadedKey = 221 SharedFilesMetadata.createKeyFromDataFile(downloadedFile, AllowedReaders.ALL_GOOGLE_APPS); 222 NewFileKey registeredKey = 223 SharedFilesMetadata.createKeyFromDataFile( 224 registeredFile, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES); 225 226 SharedFile registeredSharedFile = 227 SharedFile.newBuilder() 228 .setFileName("registered-file") 229 .setFileStatus(FileStatus.SUBSCRIBED) 230 .build(); 231 SharedFile downloadedSharedFile = 232 SharedFile.newBuilder() 233 .setFileName("downloaded-file") 234 .setFileStatus(FileStatus.DOWNLOAD_COMPLETE) 235 .build(); 236 237 synchronized (SharedPreferencesSharedFilesMetadata.class) { 238 assertThat(writeSharedFile(registeredKey, registeredSharedFile)).isTrue(); 239 assertThat(writeSharedFile(downloadedKey, downloadedSharedFile)).isTrue(); 240 } 241 242 assertThat(sharedFilesMetadata.init().get()).isTrue(); 243 244 // Check that we are able to read the file after the migration. 245 assertThat(sharedFilesMetadata.read(registeredKey).get()).isEqualTo(registeredSharedFile); 246 assertThat(sharedFilesMetadata.read(downloadedKey).get()).isEqualTo(downloadedSharedFile); 247 248 verifyNoErrorInPdsMigration(); 249 } 250 251 @Test testMigrateToNewVersion_useChecksumOnly()252 public void testMigrateToNewVersion_useChecksumOnly() 253 throws InterruptedException, ExecutionException { 254 flags.fileKeyVersion = Optional.of(FileKeyVersion.USE_CHECKSUM_ONLY.value); 255 256 Migrations.setCurrentVersion(context, FileKeyVersion.ADD_DOWNLOAD_TRANSFORM); 257 258 // Create two files, one downloaded and the other currently being downloaded. 259 DataFile registeredFile = MddTestUtil.createDataFile("registered-file", 0); 260 DataFile downloadedFile = MddTestUtil.createDataFile("downloaded-file", /* fileIndex */ 0); 261 262 NewFileKey downloadedKey = 263 SharedFilesMetadata.createKeyFromDataFile(downloadedFile, AllowedReaders.ALL_GOOGLE_APPS); 264 NewFileKey registeredKey = 265 SharedFilesMetadata.createKeyFromDataFile( 266 registeredFile, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES); 267 268 SharedFile registeredSharedFile = 269 SharedFile.newBuilder() 270 .setFileName("registered-file") 271 .setFileStatus(FileStatus.SUBSCRIBED) 272 .build(); 273 SharedFile downloadedSharedFile = 274 SharedFile.newBuilder() 275 .setFileName("downloaded-file") 276 .setFileStatus(FileStatus.DOWNLOAD_COMPLETE) 277 .build(); 278 279 synchronized (SharedPreferencesSharedFilesMetadata.class) { 280 assertThat(writeSharedFile(registeredKey, registeredSharedFile)).isTrue(); 281 assertThat(writeSharedFile(downloadedKey, downloadedSharedFile)).isTrue(); 282 } 283 284 assertThat(sharedFilesMetadata.init().get()).isTrue(); 285 286 // Check that we are able to read the file after the migration. 287 assertThat(sharedFilesMetadata.read(registeredKey).get()).isEqualTo(registeredSharedFile); 288 assertThat(sharedFilesMetadata.read(downloadedKey).get()).isEqualTo(downloadedSharedFile); 289 290 verifyNoErrorInPdsMigration(); 291 } 292 293 @Test testMigrateFromNewFileKeyToUseChecksumOnly_corruptedMetadata()294 public void testMigrateFromNewFileKeyToUseChecksumOnly_corruptedMetadata() 295 throws InterruptedException, ExecutionException { 296 flags.fileKeyVersion = Optional.of(FileKeyVersion.USE_CHECKSUM_ONLY.value); 297 298 // Create two files, one downloaded and the other currently being downloaded. 299 DataFile registeredFile = MddTestUtil.createDataFile("registered-file", 0); 300 DataFile downloadedFile = MddTestUtil.createDataFile("downloaded-file", /* fileIndex */ 0); 301 302 NewFileKey downloadedKey = 303 SharedFilesMetadata.createKeyFromDataFile(downloadedFile, AllowedReaders.ALL_GOOGLE_APPS); 304 NewFileKey registeredKey = 305 SharedFilesMetadata.createKeyFromDataFile( 306 registeredFile, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES); 307 308 SharedFile registeredSharedFile = 309 SharedFile.newBuilder() 310 .setFileName("registered-file") 311 .setFileStatus(FileStatus.SUBSCRIBED) 312 .build(); 313 SharedFile downloadedSharedFile = 314 SharedFile.newBuilder() 315 .setFileName("downloaded-file") 316 .setFileStatus(FileStatus.DOWNLOAD_COMPLETE) 317 .build(); 318 319 synchronized (SharedPreferencesSharedFilesMetadata.class) { 320 assertThat(writeSharedFile(registeredKey, registeredSharedFile)).isTrue(); 321 assertThat(writeSharedFile(downloadedKey, downloadedSharedFile)).isTrue(); 322 } 323 324 // Set invalid version 325 SharedPreferences migrationPrefs = 326 context.getSharedPreferences("gms_icing_mdd_migrations", Context.MODE_PRIVATE); 327 migrationPrefs.edit().putInt("mdd_file_key_version", 200).commit(); 328 329 assertThat(sharedFilesMetadata.init().get()).isTrue(); 330 // Check that we are able to read the file after the migration. 331 assertThat(sharedFilesMetadata.read(registeredKey).get()).isEqualTo(registeredSharedFile); 332 assertThat(sharedFilesMetadata.read(downloadedKey).get()).isEqualTo(downloadedSharedFile); 333 334 verifyNoErrorInPdsMigration(); 335 } 336 337 @Test testNoMigrate_corruptedMetadata()338 public void testNoMigrate_corruptedMetadata() throws InterruptedException, ExecutionException { 339 flags.fileKeyVersion = Optional.of(FileKeyVersion.USE_CHECKSUM_ONLY.value); 340 341 Migrations.setCurrentVersion(context, FileKeyVersion.USE_CHECKSUM_ONLY); 342 343 // Create two files, one downloaded and the other currently being downloaded. 344 DataFile registeredFile = MddTestUtil.createDataFile("registered-file", 0); 345 DataFile downloadedFile = MddTestUtil.createDataFile("downloaded-file", /* fileIndex */ 0); 346 347 NewFileKey downloadedKey = 348 SharedFilesMetadata.createKeyFromDataFile(downloadedFile, AllowedReaders.ALL_GOOGLE_APPS); 349 NewFileKey registeredKey = 350 SharedFilesMetadata.createKeyFromDataFile( 351 registeredFile, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES); 352 353 SharedFile registeredSharedFile = 354 SharedFile.newBuilder() 355 .setFileName("registered-file") 356 .setFileStatus(FileStatus.SUBSCRIBED) 357 .build(); 358 SharedFile downloadedSharedFile = 359 SharedFile.newBuilder() 360 .setFileName("downloaded-file") 361 .setFileStatus(FileStatus.DOWNLOAD_COMPLETE) 362 .build(); 363 364 synchronized (SharedPreferencesSharedFilesMetadata.class) { 365 assertThat(writeSharedFile(registeredKey, registeredSharedFile)).isTrue(); 366 assertThat(writeSharedFile(downloadedKey, downloadedSharedFile)).isTrue(); 367 } 368 369 // Set invalid version 370 SharedPreferences migrationPrefs = 371 context.getSharedPreferences("gms_icing_mdd_migrations", Context.MODE_PRIVATE); 372 migrationPrefs.edit().putInt("mdd_file_key_version", 200).commit(); 373 374 assertThat(sharedFilesMetadata.init().get()).isTrue(); 375 // Unable to read the file because the file key version doesn't match during migration 376 assertThat(sharedFilesMetadata.read(registeredKey).get()).isNull(); 377 assertThat(sharedFilesMetadata.read(downloadedKey).get()).isNull(); 378 379 verifyNoErrorInPdsMigration(); 380 } 381 382 @Test testMigrateToNewVersion_downgrade_clearOff()383 public void testMigrateToNewVersion_downgrade_clearOff() 384 throws InterruptedException, ExecutionException { 385 Migrations.setCurrentVersion(context, FileKeyVersion.ADD_DOWNLOAD_TRANSFORM); 386 flags.fileKeyVersion = Optional.of(FileKeyVersion.NEW_FILE_KEY.value); 387 388 assertThat(sharedFilesMetadata.init().get()).isFalse(); 389 } 390 391 @Test testDeserializeNewFileKey()392 public void testDeserializeNewFileKey() throws FileKeyDeserializationException { 393 Migrations.setCurrentVersion(context, FileKeyVersion.NEW_FILE_KEY); 394 String url = "https://www.gstatic.com/icing/idd/apitest/compressedFile.txt.deflate"; 395 int size = 15; 396 String checksum = "ec876850e7ddc9ecde1a3844006e3663d70569e3"; 397 NewFileKey fileKey = 398 NewFileKey.newBuilder() 399 .setUrlToDownload(url) 400 .setByteSize(size) 401 .setChecksum(checksum) 402 .setAllowedReaders(AllowedReaders.ALL_GOOGLE_APPS) 403 .build(); 404 String serializedStr = 405 SharedFilesMetadataUtil.getSerializedFileKey(fileKey, context, mockSilentFeedback); 406 NewFileKey newFileKey = 407 SharedFilesMetadataUtil.deserializeNewFileKey(serializedStr, context, mockSilentFeedback); 408 assertThat(newFileKey.getUrlToDownload()).isEqualTo(url); 409 assertThat(newFileKey.getByteSize()).isEqualTo(size); 410 assertThat(newFileKey.getChecksum()).isEqualTo(checksum); 411 assertThat(newFileKey.getAllowedReaders()).isEqualTo(AllowedReaders.ALL_GOOGLE_APPS); 412 assertThat(newFileKey.hasDownloadTransforms()).isFalse(); 413 414 // test with transforms, it should be skipped 415 String serializedStrWithDownloadTransform = 416 SharedFilesMetadataUtil.getSerializedFileKey( 417 newFileKey.toBuilder().setDownloadTransforms(COMPRESS_TRANSFORM).build(), 418 context, 419 mockSilentFeedback); 420 newFileKey = 421 SharedFilesMetadataUtil.deserializeNewFileKey( 422 serializedStrWithDownloadTransform, context, mockSilentFeedback); 423 assertThat(newFileKey.getUrlToDownload()).isEqualTo(url); 424 assertThat(newFileKey.getByteSize()).isEqualTo(size); 425 assertThat(newFileKey.getChecksum()).isEqualTo(checksum); 426 assertThat(newFileKey.getAllowedReaders()).isEqualTo(AllowedReaders.ALL_GOOGLE_APPS); 427 428 assertThat(newFileKey.hasDownloadTransforms()).isFalse(); 429 } 430 431 @Test testReadAndWriteAfterDownloadTransformMigration()432 public void testReadAndWriteAfterDownloadTransformMigration() 433 throws InterruptedException, ExecutionException { 434 Migrations.setCurrentVersion(context, FileKeyVersion.ADD_DOWNLOAD_TRANSFORM); 435 String url = "https://www.gstatic.com/icing/idd/apitest/compressedFile.txt.deflate"; 436 int size = 15; 437 String checksum = "ec876850e7ddc9ecde1a3844006e3663d70569e3"; 438 NewFileKey fileKey = 439 NewFileKey.newBuilder() 440 .setUrlToDownload(url) 441 .setByteSize(size) 442 .setChecksum(checksum) 443 .setAllowedReaders(AllowedReaders.ALL_GOOGLE_APPS) 444 .build(); 445 SharedFile sharedFile = 446 SharedFile.newBuilder() 447 .setFileName("registered-file") 448 .setFileStatus(FileStatus.DOWNLOAD_COMPLETE) 449 .build(); 450 451 // Change the same key and just add download transform 452 NewFileKey fileKeyWithTransforms = 453 fileKey.toBuilder().setDownloadTransforms(COMPRESS_TRANSFORM).build(); 454 SharedFile sharedFileWithTransform = 455 SharedFile.newBuilder() 456 .setFileName("file-with-transform") 457 .setFileStatus(FileStatus.SUBSCRIBED) 458 .build(); 459 460 synchronized (SharedPreferencesSharedFilesMetadata.class) { 461 assertThat(writeSharedFile(fileKey, sharedFile)).isTrue(); 462 assertThat(writeSharedFile(fileKeyWithTransforms, sharedFileWithTransform)).isTrue(); 463 464 assertThat(sharedFilesMetadata.read(fileKey).get()).isEqualTo(sharedFile); 465 assertThat(sharedFilesMetadata.read(fileKeyWithTransforms).get()) 466 .isEqualTo(sharedFileWithTransform); 467 468 assertThat(sharedFilesMetadata.remove(fileKey).get()).isTrue(); 469 assertThat(sharedFilesMetadata.remove(fileKeyWithTransforms).get()).isTrue(); 470 } 471 472 verifyNoErrorInPdsMigration(); 473 } 474 475 @Test testReadAndWrite_afterChecksumOnlyMigration()476 public void testReadAndWrite_afterChecksumOnlyMigration() 477 throws InterruptedException, ExecutionException { 478 Migrations.setCurrentVersion(context, FileKeyVersion.USE_CHECKSUM_ONLY); 479 480 String checksum = "ec876850e7ddc9ecde1a3844006e3663d70569e3"; 481 NewFileKey fileKey = NewFileKey.newBuilder().setChecksum(checksum).build(); 482 SharedFile sharedFile = 483 SharedFile.newBuilder() 484 .setFileName("registered-file") 485 .setFileStatus(FileStatus.DOWNLOAD_COMPLETE) 486 .build(); 487 488 synchronized (SharedPreferencesSharedFilesMetadata.class) { 489 assertThat(writeSharedFile(fileKey, sharedFile)).isTrue(); 490 assertThat(sharedFilesMetadata.read(fileKey).get()).isEqualTo(sharedFile); 491 assertThat(sharedFilesMetadata.remove(fileKey).get()).isTrue(); 492 } 493 494 verifyNoErrorInPdsMigration(); 495 } 496 497 @Test testGetAllFileKeys_afterDownloadTransformMigration()498 public void testGetAllFileKeys_afterDownloadTransformMigration() 499 throws InterruptedException, ExecutionException { 500 Migrations.setCurrentVersion(context, FileKeyVersion.ADD_DOWNLOAD_TRANSFORM); 501 String url = "https://www.gstatic.com/icing/idd/apitest/compressedFile.txt.deflate"; 502 int size = 15; 503 String checksum = "ec876850e7ddc9ecde1a3844006e3663d70569e3"; 504 NewFileKey fileKey = 505 NewFileKey.newBuilder() 506 .setUrlToDownload(url) 507 .setByteSize(size) 508 .setChecksum(checksum) 509 .setAllowedReaders(AllowedReaders.ALL_GOOGLE_APPS) 510 .build(); 511 SharedFile sharedFile = 512 SharedFile.newBuilder() 513 .setFileName("registered-file") 514 .setFileStatus(FileStatus.DOWNLOAD_COMPLETE) 515 .build(); 516 517 // Change the same key and just add download transform 518 NewFileKey fileKeyWithTransforms = 519 fileKey.toBuilder().setDownloadTransforms(COMPRESS_TRANSFORM).build(); 520 SharedFile sharedFileWithTransform = 521 SharedFile.newBuilder() 522 .setFileName("file-with-transform") 523 .setFileStatus(FileStatus.SUBSCRIBED) 524 .build(); 525 526 synchronized (SharedPreferencesSharedFilesMetadata.class) { 527 assertThat(writeSharedFile(fileKey, sharedFile)).isTrue(); 528 assertThat(writeSharedFile(fileKeyWithTransforms, sharedFileWithTransform)).isTrue(); 529 530 List<NewFileKey> allFileKeys = sharedFilesMetadata.getAllFileKeys().get(); 531 assertThat(allFileKeys).hasSize(2); 532 } 533 } 534 535 @Test testGetAllFileKeys_afterChecksumOnlyMigration()536 public void testGetAllFileKeys_afterChecksumOnlyMigration() 537 throws InterruptedException, ExecutionException { 538 Migrations.setCurrentVersion(context, FileKeyVersion.USE_CHECKSUM_ONLY); 539 540 String checksum = "ec876850e7ddc9ecde1a3844006e3663d70569e3"; 541 NewFileKey fileKey = 542 NewFileKey.newBuilder() 543 .setChecksum(checksum) 544 .setAllowedReaders(AllowedReaders.ALL_GOOGLE_APPS) 545 .build(); 546 SharedFile sharedFile = 547 SharedFile.newBuilder() 548 .setFileName("registered-file") 549 .setFileStatus(FileStatus.DOWNLOAD_COMPLETE) 550 .build(); 551 552 synchronized (SharedPreferencesSharedFilesMetadata.class) { 553 assertThat(writeSharedFile(fileKey, sharedFile)).isTrue(); 554 555 List<NewFileKey> allFileKeys = sharedFilesMetadata.getAllFileKeys().get(); 556 assertThat(allFileKeys).hasSize(1); 557 assertThat(allFileKeys.get(0)).isEqualTo(fileKey); 558 } 559 } 560 561 @Test testGetAllFileKeysWithCorruptedData()562 public void testGetAllFileKeysWithCorruptedData() 563 throws InterruptedException, ExecutionException { 564 SharedPreferences prefs = 565 SharedPreferencesUtil.getSharedPreferences( 566 context, SharedFilesMetadataUtil.MDD_SHARED_FILES, instanceId); 567 String validKeyOne = 568 "https://www.gstatic.com/icing/idd/apitest/compressedFile.txt.deflate|15|checksum|1"; 569 String corruptedKeyOne = 570 "https://www.gstatic.com/icing/idd/apitest/compressedFile.txt.deflate|15|abc"; 571 SharedFile sharedFile = 572 SharedFile.newBuilder() 573 .setFileName("registered-file") 574 .setFileStatus(FileStatus.DOWNLOAD_COMPLETE) 575 .build(); 576 assertThat(SharedPreferencesUtil.writeProto(prefs, validKeyOne, sharedFile)).isTrue(); 577 assertThat(SharedPreferencesUtil.writeProto(prefs, corruptedKeyOne, sharedFile)).isTrue(); 578 String corruptedKeyTwo = "|15|abc"; 579 assertThat(SharedPreferencesUtil.writeProto(prefs, corruptedKeyTwo, sharedFile)).isTrue(); 580 assertThat(sharedFilesMetadata.getAllFileKeys().get()).hasSize(1); 581 assertThat( 582 SharedPreferencesUtil.getSharedPreferences( 583 context, SharedFilesMetadataUtil.MDD_SHARED_FILES, instanceId) 584 .getAll()) 585 .hasSize(1); 586 } 587 588 @Test test_createKeyFromDataFile_withZipDownloadTransform()589 public void test_createKeyFromDataFile_withZipDownloadTransform() { 590 DataFile zipFile = MddTestUtil.createZipFolderDataFile("testzip", 0); 591 NewFileKey fileKey = 592 SharedFilesMetadata.createKeyFromDataFile(zipFile, AllowedReaders.ALL_GOOGLE_APPS); 593 assertThat(fileKey.getChecksum()).isEqualTo(zipFile.getDownloadedFileChecksum()); 594 } 595 writeSharedFile(NewFileKey newFileKey, SharedFile sharedFile)596 private boolean writeSharedFile(NewFileKey newFileKey, SharedFile sharedFile) 597 throws InterruptedException, ExecutionException { 598 return sharedFilesMetadata.write(newFileKey, sharedFile).get(); 599 } 600 verifyNoErrorInPdsMigration()601 private void verifyNoErrorInPdsMigration() {} 602 } 603