• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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