diff options
author | Presubmit Automerger Backend <android-build-presubmit-automerger-backend@system.gserviceaccount.com> | 2023-02-10 04:03:40 +0000 |
---|---|---|
committer | Presubmit Automerger Backend <android-build-presubmit-automerger-backend@system.gserviceaccount.com> | 2023-02-10 04:03:40 +0000 |
commit | 3436fde574dfb794d2c3333f6554298c3baa74cf (patch) | |
tree | 74a728b387cb64e67cf995b48db539e22dc633d7 | |
parent | 892a6ecb5404bcfb4905f5573a38ff58b1e1b995 (diff) | |
parent | d765889fb9cbfc16d999873dec4ecc34c48830f4 (diff) | |
download | mobile-data-download-3436fde574dfb794d2c3333f6554298c3baa74cf.tar.gz |
[automerge] Disable unsupported robolectric tests. 2p: d765889fb9
Original change: https://googleplex-android-review.googlesource.com/c/platform/external/mobile-data-download/+/21355002
Bug: 268508749
Change-Id: Ie9145a4fd575163b9958776a815189f960c2cef4
4 files changed, 1005 insertions, 947 deletions
diff --git a/javatests/Android.bp b/javatests/Android.bp index 12c9fbb..d88eaad 100644 --- a/javatests/Android.bp +++ b/javatests/Android.bp @@ -42,6 +42,7 @@ android_robolectric_test { "com/google/android/libraries/mobiledatadownload/internal/MobileDataDownloadManagerTest.java", // Missing LabsFutures "com/google/android/libraries/mobiledatadownload/internal/FileGroupManagerTest.java", // Missing LabsFutures "com/google/android/libraries/mobiledatadownload/internal/util/ProtoConversionUtilTest.java", // Missing ProtoParsers + "com/google/android/libraries/mobiledatadownload/internal/MddIsolatedStructuresTest.java", //android.os.symlink and android.os.readlink do not work with robolectric ], java_resource_dirs: ["config"], diff --git a/javatests/com/google/android/libraries/mobiledatadownload/internal/MddIsolatedStructuresTest.java b/javatests/com/google/android/libraries/mobiledatadownload/internal/MddIsolatedStructuresTest.java index e5b9574..7c16830 100644 --- a/javatests/com/google/android/libraries/mobiledatadownload/internal/MddIsolatedStructuresTest.java +++ b/javatests/com/google/android/libraries/mobiledatadownload/internal/MddIsolatedStructuresTest.java @@ -16,12 +16,14 @@ package com.google.android.libraries.mobiledatadownload.internal; import static com.google.common.truth.Truth.assertThat; + import static java.nio.charset.StandardCharsets.UTF_16; import android.content.Context; import android.net.Uri; + import androidx.test.core.app.ApplicationProvider; -import org.robolectric.RobolectricTestRunner; + import com.google.android.libraries.mobiledatadownload.SilentFeedback; import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage; import com.google.android.libraries.mobiledatadownload.file.backends.AndroidFileBackend; @@ -47,9 +49,7 @@ import com.google.mobiledatadownload.internal.MetadataProto.FileStatus; import com.google.mobiledatadownload.internal.MetadataProto.GroupKey; import com.google.mobiledatadownload.internal.MetadataProto.NewFileKey; import com.google.mobiledatadownload.internal.MetadataProto.SharedFile; -import java.util.Arrays; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -57,6 +57,11 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; + +import java.util.Arrays; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; /** * Emulator tests for MDD isolated structures support. This is separate from the other robolectric diff --git a/javatests/com/google/android/libraries/mobiledatadownload/internal/SharedFileManagerTest.java b/javatests/com/google/android/libraries/mobiledatadownload/internal/SharedFileManagerTest.java index dbc3077..6e3b7e1 100644 --- a/javatests/com/google/android/libraries/mobiledatadownload/internal/SharedFileManagerTest.java +++ b/javatests/com/google/android/libraries/mobiledatadownload/internal/SharedFileManagerTest.java @@ -17,6 +17,7 @@ package com.google.android.libraries.mobiledatadownload.internal; import static com.google.android.libraries.mobiledatadownload.internal.SharedFileManager.MDD_SHARED_FILE_MANAGER_METADATA; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyList; @@ -25,13 +26,16 @@ import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import android.content.Context; import android.content.SharedPreferences; import android.net.Uri; import android.os.Build; + import androidx.test.core.app.ApplicationProvider; + import com.google.android.libraries.mobiledatadownload.DownloadException; import com.google.android.libraries.mobiledatadownload.DownloadException.DownloadResultCode; import com.google.android.libraries.mobiledatadownload.FileSource; @@ -67,14 +71,7 @@ import com.google.mobiledatadownload.internal.MetadataProto.GroupKey; import com.google.mobiledatadownload.internal.MetadataProto.NewFileKey; import com.google.mobiledatadownload.internal.MetadataProto.SharedFile; import com.google.protobuf.ByteString; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; + import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -90,917 +87,961 @@ import org.robolectric.ParameterizedRobolectricTestRunner.Parameters; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + @RunWith(ParameterizedRobolectricTestRunner.class) @Config(shadows = {}) public class SharedFileManagerTest { - @Parameters( - name = - "runAfterMigratedToAddDownloadTransform = {0}, runAfterMigratedToUseChecksumOnly = {1}") - public static Collection<Object[]> parameters() { - return Arrays.asList(new Object[][] {{false, false}, {true, false}, {true, true}}); - } - - @Parameter(value = 0) - public boolean runAfterMigratedToAddDownloadTransform; - - @Parameter(value = 1) - public boolean runAfterMigratedToUseChecksumOnly; - - private static final DownloadConditions DOWNLOAD_CONDITIONS = - DownloadConditions.getDefaultInstance(); - - private static final int TRAFFIC_TAG = 1000; - - private Context context; - private SynchronousFileStorage fileStorage; - private static final long FILE_GROUP_EXPIRATION_DATE_SECS = 10; - private static final String TEST_GROUP = "test-group"; - private static final int VERSION_NUMBER = 7; - private static final long BUILD_ID = 0; - private static final DataFileGroupInternal FILE_GROUP = - MddTestUtil.createDataFileGroupInternal(TEST_GROUP, 1).toBuilder() - .setFileGroupVersionNumber(VERSION_NUMBER) - .build(); - private static final GroupKey GROUP_KEY = - FileGroupUtil.createGroupKey(FILE_GROUP.getGroupName(), FILE_GROUP.getOwnerPackage()); - private static final Executor CONTROL_EXECUTOR = - MoreExecutors.newSequentialExecutor(Executors.newCachedThreadPool()); - private SharedFileManager sfm; - - // This is currently not mocked as the class was split from SharedFileManager, and this ensures - // that all tests still run the same way. - private SharedFilesMetadata sharedFilesMetadata; - private File publicDirectory; - private File privateDirectory; - private Optional<DeltaDecoder> deltaDecoder; - private final TestFlags flags = new TestFlags(); - @Mock SilentFeedback mockSilentFeedback; - @Mock MddFileDownloader mockDownloader; - @Mock DownloadProgressMonitor mockDownloadMonitor; - @Mock EventLogger eventLogger; - @Mock FileGroupsMetadata fileGroupsMetadata; - @Mock Backend mockBackend; - - @Rule public final MockitoRule mocks = MockitoJUnit.rule(); - - @Before - public void setUp() throws Exception { - - context = ApplicationProvider.getApplicationContext(); - - when(mockBackend.name()).thenReturn("blobstore"); - fileStorage = - new SynchronousFileStorage( - Arrays.asList(AndroidFileBackend.builder(context).build(), mockBackend), - ImmutableList.of(new CompressTransform())); - - sharedFilesMetadata = - new SharedPreferencesSharedFilesMetadata( - context, mockSilentFeedback, Optional.absent(), flags); - - deltaDecoder = Optional.absent(); - sfm = - new SharedFileManager( - context, - mockSilentFeedback, - sharedFilesMetadata, - fileStorage, - mockDownloader, - deltaDecoder, - Optional.of(mockDownloadMonitor), - eventLogger, - flags, - fileGroupsMetadata, - Optional.absent(), - CONTROL_EXECUTOR); - - // TODO(b/117571083): Replace with fileStorage API. - File downloadDirectory = - new File(context.getFilesDir(), DirectoryUtil.MDD_STORAGE_MODULE + "/" + "shared"); - publicDirectory = new File(downloadDirectory, DirectoryUtil.MDD_STORAGE_ALL_GOOGLE_APPS); - privateDirectory = - new File(downloadDirectory, DirectoryUtil.MDD_STORAGE_ONLY_GOOGLE_PLAY_SERVICES); - publicDirectory.mkdirs(); - privateDirectory.mkdirs(); - - if (runAfterMigratedToUseChecksumOnly) { - Migrations.setCurrentVersion(context, FileKeyVersion.USE_CHECKSUM_ONLY); - } else if (runAfterMigratedToAddDownloadTransform) { - Migrations.setCurrentVersion(context, FileKeyVersion.ADD_DOWNLOAD_TRANSFORM); - } - } - - @After - public void tearDown() throws Exception { - SharedPreferencesUtil.getSharedPreferences( - context, MDD_SHARED_FILE_MANAGER_METADATA, Optional.absent()) - .edit() - .clear() - .commit(); - - // Reset to avoid exception in the call below. - fileStorage.deleteRecursively( - DirectoryUtil.getBaseDownloadDirectory(context, Optional.absent())); - } - - @Test - public void init_migrateToNewKey_enabled_v23ToV24() throws Exception { - Migrations.setMigratedToNewFileKey(context, false); - - assertThat(Migrations.isMigratedToNewFileKey(context)).isFalse(); - - SharedPreferences sfmMetadata = + @Parameters( + name = + "runAfterMigratedToAddDownloadTransform = {0}, " + + "runAfterMigratedToUseChecksumOnly = {1}") + public static Collection<Object[]> parameters() { + return Arrays.asList(new Object[][]{{false, false}, {true, false}, {true, true}}); + } + + @Parameter(value = 0) + public boolean runAfterMigratedToAddDownloadTransform; + + @Parameter(value = 1) + public boolean runAfterMigratedToUseChecksumOnly; + + private static final DownloadConditions DOWNLOAD_CONDITIONS = + DownloadConditions.getDefaultInstance(); + + private static final int TRAFFIC_TAG = 1000; + + private Context context; + private SynchronousFileStorage fileStorage; + private static final long FILE_GROUP_EXPIRATION_DATE_SECS = 10; + private static final String TEST_GROUP = "test-group"; + private static final int VERSION_NUMBER = 7; + private static final long BUILD_ID = 0; + private static final DataFileGroupInternal FILE_GROUP = + MddTestUtil.createDataFileGroupInternal(TEST_GROUP, 1).toBuilder() + .setFileGroupVersionNumber(VERSION_NUMBER) + .build(); + private static final GroupKey GROUP_KEY = + FileGroupUtil.createGroupKey(FILE_GROUP.getGroupName(), FILE_GROUP.getOwnerPackage()); + private static final Executor CONTROL_EXECUTOR = + MoreExecutors.newSequentialExecutor(Executors.newCachedThreadPool()); + private SharedFileManager sfm; + + // This is currently not mocked as the class was split from SharedFileManager, and this ensures + // that all tests still run the same way. + private SharedFilesMetadata sharedFilesMetadata; + private File publicDirectory; + private File privateDirectory; + private Optional<DeltaDecoder> deltaDecoder; + private final TestFlags flags = new TestFlags(); + @Mock + SilentFeedback mockSilentFeedback; + @Mock + MddFileDownloader mockDownloader; + @Mock + DownloadProgressMonitor mockDownloadMonitor; + @Mock + EventLogger eventLogger; + @Mock + FileGroupsMetadata fileGroupsMetadata; + @Mock + Backend mockBackend; + + @Rule + public final MockitoRule mocks = MockitoJUnit.rule(); + + @Before + public void setUp() throws Exception { + + context = ApplicationProvider.getApplicationContext(); + + when(mockBackend.name()).thenReturn("blobstore"); + fileStorage = + new SynchronousFileStorage( + Arrays.asList(AndroidFileBackend.builder(context).build(), mockBackend), + ImmutableList.of(new CompressTransform())); + + sharedFilesMetadata = + new SharedPreferencesSharedFilesMetadata( + context, mockSilentFeedback, Optional.absent(), flags); + + deltaDecoder = Optional.absent(); + sfm = + new SharedFileManager( + context, + mockSilentFeedback, + sharedFilesMetadata, + fileStorage, + mockDownloader, + deltaDecoder, + Optional.of(mockDownloadMonitor), + eventLogger, + flags, + fileGroupsMetadata, + Optional.absent(), + CONTROL_EXECUTOR); + + // TODO(b/117571083): Replace with fileStorage API. + File downloadDirectory = + new File(context.getFilesDir(), DirectoryUtil.MDD_STORAGE_MODULE + "/" + "shared"); + publicDirectory = new File(downloadDirectory, DirectoryUtil.MDD_STORAGE_ALL_GOOGLE_APPS); + privateDirectory = + new File(downloadDirectory, DirectoryUtil.MDD_STORAGE_ONLY_GOOGLE_PLAY_SERVICES); + publicDirectory.mkdirs(); + privateDirectory.mkdirs(); + + if (runAfterMigratedToUseChecksumOnly) { + Migrations.setCurrentVersion(context, FileKeyVersion.USE_CHECKSUM_ONLY); + } else if (runAfterMigratedToAddDownloadTransform) { + Migrations.setCurrentVersion(context, FileKeyVersion.ADD_DOWNLOAD_TRANSFORM); + } + } + + @After + public void tearDown() throws Exception { SharedPreferencesUtil.getSharedPreferences( - context, MDD_SHARED_FILE_MANAGER_METADATA, Optional.absent()); - sfmMetadata - .edit() - .putBoolean(SharedFileManager.PREFS_KEY_MIGRATED_TO_NEW_FILE_KEY, true) - .commit(); - - assertThat(sfm.init().get()).isTrue(); - - assertThat(Migrations.isMigratedToNewFileKey(context)).isTrue(); - } - - @Test - public void testSubscribeAndUnsubscribeSingleFile() throws Exception { - DataFile file = MddTestUtil.createDataFile("fileId", 0); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - - // Make sure the file entry was stored. - assertThat(sharedFilesMetadata.read(newFileKey)).isNotNull(); - - // Unsubscribe and ensure entry for file was deleted. - assertThat(sfm.removeFileEntry(newFileKey).get()).isTrue(); - assertThat(sharedFilesMetadata.read(newFileKey).get()).isNull(); - } - - @Test - public void testMultipleSubscribes() throws Exception { - DataFile file = MddTestUtil.createDataFile("fileId", 0); - - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - - // Unsubscribe once. It should not matter how many subscribes were previously called. An - // unsubscribe should remove the entry. - assertThat(sfm.removeFileEntry(newFileKey).get()).isTrue(); - assertThat(sharedFilesMetadata.read(newFileKey).get()).isNull(); - } - -// TODO: (b/239218521) Test will be ready once mockto v4 is available -// @Test -// public void testRemoveFileEntry_nonexistentFile() throws Exception { -// DataFile file = MddTestUtil.createDataFile("fileId", 0); - -// // Try to unsubscribe from a file that was never subscribed to and ensure that this won't add -// // an entry for the file. -// NewFileKey newFileKey = -// SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); -// assertThat(sfm.removeFileEntry(newFileKey).get()).isFalse(); -// assertThat(sharedFilesMetadata.read(newFileKey).get()).isNull(); - -// verifyNoInteractions(mockDownloader); -// } - - @Test - public void testRemoveFileEntry_partialDownloadFileNotDeleted() throws Exception { - DataFile file = MddTestUtil.createDataFile("fileId", 0); - - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - - // Download the file, but do not update shared prefs to say it is downloaded. - File onDeviceFile = simulateDownload(file, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); - - assertThat(onDeviceFile.exists()).isTrue(); - - Uri uri = sfm.getOnDeviceUri(newFileKey).get(); - - // Ensure that deregister has actually deleted the file on disk. - assertThat(sfm.removeFileEntry(newFileKey).get()).isTrue(); - assertThat(sharedFilesMetadata.read(newFileKey).get()).isNull(); - // The partial download file should be deleted - assertThat(onDeviceFile.exists()).isTrue(); - - verify(mockDownloader).stopDownloading(uri); - } - - @Test - public void testStartImport_startsInlineFileCopy() throws Exception { - FileSource inlineSource = FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT")); - DataFile file = - MddTestUtil.createDataFile("fileId", 0).toBuilder() - .setUrlToDownload("inlinefile:123") - .build(); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - Uri fileUri = sfm.getOnDeviceUri(newFileKey).get(); - when(fileGroupsMetadata.read(GROUP_KEY)).thenReturn(Futures.immediateFuture(FILE_GROUP)); - when(mockDownloader.startCopying( - eq(fileUri), - eq(file.getUrlToDownload()), - eq(file.getByteSize()), - eq(DOWNLOAD_CONDITIONS), - isA(DownloaderCallbackImpl.class), - any())) - .thenReturn(Futures.immediateVoidFuture()); - - sfm.startImport(GROUP_KEY, file, newFileKey, DOWNLOAD_CONDITIONS, inlineSource).get(); - - SharedFile sharedFile = sharedFilesMetadata.read(newFileKey).get(); - assertThat(sharedFile.getFileStatus()).isEqualTo(FileStatus.DOWNLOAD_IN_PROGRESS); - } - - @Test - public void testStartImport_whenFileAlreadyDownloaded_returnsEarly() throws Exception { - FileSource inlineSource = FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT")); - DataFile file = - MddTestUtil.createDataFile("fileId", 0).toBuilder() - .setUrlToDownload("inlinefile:123") - .build(); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - File onDeviceFile = simulateDownload(file, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); - changeFileStatusAs(newFileKey, FileStatus.DOWNLOAD_COMPLETE); - - // File is already downloaded, so we should return early - sfm.startImport(GROUP_KEY, file, newFileKey, DOWNLOAD_CONDITIONS, inlineSource).get(); - onDeviceFile.delete(); - - verify(mockDownloader, times(0)).startCopying(any(), any(), anyInt(), any(), any(), any()); - } - - @Test - public void testStartImport_whenUnreservedEntry_throws() throws Exception { - FileSource inlineSource = FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT")); - DataFile file = - MddTestUtil.createDataFile("fileId", 0).toBuilder() - .setUrlToDownload("inlinefile:123") - .build(); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - - ExecutionException ex = - Assert.assertThrows( - ExecutionException.class, - () -> - sfm.startImport(GROUP_KEY, file, newFileKey, DOWNLOAD_CONDITIONS, inlineSource) - .get()); - - assertThat(ex).hasCauseThat().isInstanceOf(DownloadException.class); - DownloadException dex = (DownloadException) ex.getCause(); - - assertThat(dex.getDownloadResultCode()) - .isEqualTo(DownloadResultCode.SHARED_FILE_NOT_FOUND_ERROR); - } - - @Test - public void testStartImport_whenNotInlineFileUrlScheme_throws() throws Exception { - FileSource inlineSource = FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT")); - DataFile file = MddTestUtil.createDataFile("fileId", 0); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - - ExecutionException ex = - Assert.assertThrows( - ExecutionException.class, - () -> - sfm.startImport(GROUP_KEY, file, newFileKey, DOWNLOAD_CONDITIONS, inlineSource) - .get()); - - assertThat(ex).hasCauseThat().isInstanceOf(DownloadException.class); - DownloadException dex = (DownloadException) ex.getCause(); - assertThat(dex.getDownloadResultCode()) - .isEqualTo(DownloadResultCode.INVALID_INLINE_FILE_URL_SCHEME); - } - - @Test - public void testNotifyCurrentSize_partialDownloadFile() throws Exception { - DataFile file = MddTestUtil.createDataFile("fileId", 0); - - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - - // Download the file, but do not update shared prefs to say it is downloaded. - File onDeviceFile = simulateDownload(file, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); - Uri fileUri = sfm.getOnDeviceUri(newFileKey).get(); - - when(fileGroupsMetadata.read(GROUP_KEY)).thenReturn(Futures.immediateFuture(FILE_GROUP)); - when(mockDownloader.startDownloading( - eq(GROUP_KEY), - eq(VERSION_NUMBER), - eq(BUILD_ID), - eq(fileUri), - eq(file.getUrlToDownload()), - eq(file.getByteSize()), - eq(DOWNLOAD_CONDITIONS), - isA(DownloaderCallbackImpl.class), - anyInt(), - anyList())) - .thenReturn(Futures.immediateFuture(null)); - - sfm.startDownload( - GROUP_KEY, - file, - newFileKey, - DOWNLOAD_CONDITIONS, - TRAFFIC_TAG, - /*extraHttpHeaders = */ ImmutableList.of()) - .get(); - - SharedFile sharedFile = sharedFilesMetadata.read(newFileKey).get(); - assertThat(sharedFile.getFileStatus()).isEqualTo(FileStatus.DOWNLOAD_IN_PROGRESS); - verify(mockDownloadMonitor).notifyCurrentFileSize(TEST_GROUP, onDeviceFile.length()); - } - - @Test - public void testDontDeleteUnsubscribedFiles() throws Exception { - DataFile datafile = MddTestUtil.createDataFile("fileId", 0); - - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(datafile, AllowedReaders.ALL_GOOGLE_APPS); - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - - // "download" the file and update sharedPrefs - File onDeviceFile = - simulateDownload(datafile, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); - changeFileStatusAs(newFileKey, FileStatus.DOWNLOAD_COMPLETE); - - assertThat(onDeviceFile.exists()).isTrue(); - Uri uri = sfm.getOnDeviceUri(newFileKey).get(); - - // Ensure that deregister has actually deleted the file on disk. - assertThat(sfm.removeFileEntry(newFileKey).get()).isTrue(); - assertThat(sharedFilesMetadata.read(newFileKey).get()).isNull(); - // The file should not be deleted by the SFM because deletion is handled by ExpirationHandler. - assertThat(onDeviceFile.exists()).isTrue(); - - verify(mockDownloader).stopDownloading(uri); - } - - @Test - public void testStartDownload_whenInlineFileUrlScheme_fails() throws Exception { - DataFile inlineFile = - MddTestUtil.createDataFile("inlineFileId", 0).toBuilder() - .setUrlToDownload("inlinefile:abc") - .setChecksum("abc") - .build(); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(inlineFile, AllowedReaders.ALL_GOOGLE_APPS); - - ExecutionException ex = - Assert.assertThrows( - ExecutionException.class, - () -> - sfm.startDownload( + context, MDD_SHARED_FILE_MANAGER_METADATA, Optional.absent()) + .edit() + .clear() + .commit(); + + // Reset to avoid exception in the call below. + fileStorage.deleteRecursively( + DirectoryUtil.getBaseDownloadDirectory(context, Optional.absent())); + } + + @Test + public void init_migrateToNewKey_enabled_v23ToV24() throws Exception { + Migrations.setMigratedToNewFileKey(context, false); + + assertThat(Migrations.isMigratedToNewFileKey(context)).isFalse(); + + SharedPreferences sfmMetadata = + SharedPreferencesUtil.getSharedPreferences( + context, MDD_SHARED_FILE_MANAGER_METADATA, Optional.absent()); + sfmMetadata + .edit() + .putBoolean(SharedFileManager.PREFS_KEY_MIGRATED_TO_NEW_FILE_KEY, true) + .commit(); + + assertThat(sfm.init().get()).isTrue(); + + assertThat(Migrations.isMigratedToNewFileKey(context)).isTrue(); + } + + @Test + public void testSubscribeAndUnsubscribeSingleFile() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + + // Make sure the file entry was stored. + assertThat(sharedFilesMetadata.read(newFileKey)).isNotNull(); + + // Unsubscribe and ensure entry for file was deleted. + assertThat(sfm.removeFileEntry(newFileKey).get()).isTrue(); + assertThat(sharedFilesMetadata.read(newFileKey).get()).isNull(); + } + + @Test + public void testMultipleSubscribes() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + + // Unsubscribe once. It should not matter how many subscribes were previously called. An + // unsubscribe should remove the entry. + assertThat(sfm.removeFileEntry(newFileKey).get()).isTrue(); + assertThat(sharedFilesMetadata.read(newFileKey).get()).isNull(); + } + + @Test + public void testRemoveFileEntry_nonexistentFile() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + + // Try to unsubscribe from a file that was never subscribed to and ensure that this won't + // add + // an entry for the file. + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + assertThat(sfm.removeFileEntry(newFileKey).get()).isFalse(); + assertThat(sharedFilesMetadata.read(newFileKey).get()).isNull(); + + verifyNoInteractions(mockDownloader); + } + + @Test + public void testRemoveFileEntry_partialDownloadFileNotDeleted() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + + // Download the file, but do not update shared prefs to say it is downloaded. + File onDeviceFile = simulateDownload(file, getLastFileName(), + AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(onDeviceFile.exists()).isTrue(); + + Uri uri = sfm.getOnDeviceUri(newFileKey).get(); + + // Ensure that deregister has actually deleted the file on disk. + assertThat(sfm.removeFileEntry(newFileKey).get()).isTrue(); + assertThat(sharedFilesMetadata.read(newFileKey).get()).isNull(); + // The partial download file should be deleted + assertThat(onDeviceFile.exists()).isTrue(); + + verify(mockDownloader).stopDownloading(uri); + } + + @Test + public void testStartImport_startsInlineFileCopy() throws Exception { + FileSource inlineSource = FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT")); + DataFile file = + MddTestUtil.createDataFile("fileId", 0).toBuilder() + .setUrlToDownload("inlinefile:123") + .build(); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + Uri fileUri = sfm.getOnDeviceUri(newFileKey).get(); + when(fileGroupsMetadata.read(GROUP_KEY)).thenReturn(Futures.immediateFuture(FILE_GROUP)); + when(mockDownloader.startCopying( + eq(fileUri), + eq(file.getUrlToDownload()), + eq(file.getByteSize()), + eq(DOWNLOAD_CONDITIONS), + isA(DownloaderCallbackImpl.class), + any())) + .thenReturn(Futures.immediateVoidFuture()); + + sfm.startImport(GROUP_KEY, file, newFileKey, DOWNLOAD_CONDITIONS, inlineSource).get(); + + SharedFile sharedFile = sharedFilesMetadata.read(newFileKey).get(); + assertThat(sharedFile.getFileStatus()).isEqualTo(FileStatus.DOWNLOAD_IN_PROGRESS); + } + + @Test + public void testStartImport_whenFileAlreadyDownloaded_returnsEarly() throws Exception { + FileSource inlineSource = FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT")); + DataFile file = + MddTestUtil.createDataFile("fileId", 0).toBuilder() + .setUrlToDownload("inlinefile:123") + .build(); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + File onDeviceFile = simulateDownload(file, getLastFileName(), + AllowedReaders.ALL_GOOGLE_APPS); + changeFileStatusAs(newFileKey, FileStatus.DOWNLOAD_COMPLETE); + + // File is already downloaded, so we should return early + sfm.startImport(GROUP_KEY, file, newFileKey, DOWNLOAD_CONDITIONS, inlineSource).get(); + onDeviceFile.delete(); + + verify(mockDownloader, times(0)).startCopying(any(), any(), anyInt(), any(), any(), any()); + } + + @Test + public void testStartImport_whenUnreservedEntry_throws() throws Exception { + FileSource inlineSource = FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT")); + DataFile file = + MddTestUtil.createDataFile("fileId", 0).toBuilder() + .setUrlToDownload("inlinefile:123") + .build(); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + ExecutionException ex = + Assert.assertThrows( + ExecutionException.class, + () -> + sfm.startImport(GROUP_KEY, file, newFileKey, DOWNLOAD_CONDITIONS, + inlineSource) + .get()); + + assertThat(ex).hasCauseThat().isInstanceOf(DownloadException.class); + DownloadException dex = (DownloadException) ex.getCause(); + + assertThat(dex.getDownloadResultCode()) + .isEqualTo(DownloadResultCode.SHARED_FILE_NOT_FOUND_ERROR); + } + + @Test + public void testStartImport_whenNotInlineFileUrlScheme_throws() throws Exception { + FileSource inlineSource = FileSource.ofByteString(ByteString.copyFromUtf8("TEST_CONTENT")); + DataFile file = MddTestUtil.createDataFile("fileId", 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + ExecutionException ex = + Assert.assertThrows( + ExecutionException.class, + () -> + sfm.startImport(GROUP_KEY, file, newFileKey, DOWNLOAD_CONDITIONS, + inlineSource) + .get()); + + assertThat(ex).hasCauseThat().isInstanceOf(DownloadException.class); + DownloadException dex = (DownloadException) ex.getCause(); + assertThat(dex.getDownloadResultCode()) + .isEqualTo(DownloadResultCode.INVALID_INLINE_FILE_URL_SCHEME); + } + + @Test + public void testNotifyCurrentSize_partialDownloadFile() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + + // Download the file, but do not update shared prefs to say it is downloaded. + File onDeviceFile = simulateDownload(file, getLastFileName(), + AllowedReaders.ALL_GOOGLE_APPS); + Uri fileUri = sfm.getOnDeviceUri(newFileKey).get(); + + when(fileGroupsMetadata.read(GROUP_KEY)).thenReturn(Futures.immediateFuture(FILE_GROUP)); + when(mockDownloader.startDownloading( + eq(GROUP_KEY), + eq(VERSION_NUMBER), + eq(BUILD_ID), + eq(fileUri), + eq(file.getUrlToDownload()), + eq(file.getByteSize()), + eq(DOWNLOAD_CONDITIONS), + isA(DownloaderCallbackImpl.class), + anyInt(), + anyList())) + .thenReturn(Futures.immediateFuture(null)); + + sfm.startDownload( GROUP_KEY, - inlineFile, + file, + newFileKey, + DOWNLOAD_CONDITIONS, + TRAFFIC_TAG, + /*extraHttpHeaders = */ ImmutableList.of()) + .get(); + + SharedFile sharedFile = sharedFilesMetadata.read(newFileKey).get(); + assertThat(sharedFile.getFileStatus()).isEqualTo(FileStatus.DOWNLOAD_IN_PROGRESS); + verify(mockDownloadMonitor).notifyCurrentFileSize(TEST_GROUP, onDeviceFile.length()); + } + + @Test + public void testDontDeleteUnsubscribedFiles() throws Exception { + DataFile datafile = MddTestUtil.createDataFile("fileId", 0); + + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(datafile, AllowedReaders.ALL_GOOGLE_APPS); + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + + // "download" the file and update sharedPrefs + File onDeviceFile = + simulateDownload(datafile, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); + changeFileStatusAs(newFileKey, FileStatus.DOWNLOAD_COMPLETE); + + assertThat(onDeviceFile.exists()).isTrue(); + Uri uri = sfm.getOnDeviceUri(newFileKey).get(); + + // Ensure that deregister has actually deleted the file on disk. + assertThat(sfm.removeFileEntry(newFileKey).get()).isTrue(); + assertThat(sharedFilesMetadata.read(newFileKey).get()).isNull(); + // The file should not be deleted by the SFM because deletion is handled by + // ExpirationHandler. + assertThat(onDeviceFile.exists()).isTrue(); + + verify(mockDownloader).stopDownloading(uri); + } + + @Test + public void testStartDownload_whenInlineFileUrlScheme_fails() throws Exception { + DataFile inlineFile = + MddTestUtil.createDataFile("inlineFileId", 0).toBuilder() + .setUrlToDownload("inlinefile:abc") + .setChecksum("abc") + .build(); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(inlineFile, + AllowedReaders.ALL_GOOGLE_APPS); + + ExecutionException ex = + Assert.assertThrows( + ExecutionException.class, + () -> + sfm.startDownload( + GROUP_KEY, + inlineFile, + newFileKey, + DOWNLOAD_CONDITIONS, + TRAFFIC_TAG, + /* extraHttpHeaders = */ ImmutableList.of()) + .get()); + assertThat(ex).hasCauseThat().isInstanceOf(DownloadException.class); + DownloadException dex = (DownloadException) ex.getCause(); + assertThat(dex.getDownloadResultCode()) + .isEqualTo(DownloadResultCode.INVALID_INLINE_FILE_URL_SCHEME); + } + + @Test + public void testStartDownload_unsubscribedFile() { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + ExecutionException ex = + Assert.assertThrows( + ExecutionException.class, + () -> + sfm.startDownload( + GROUP_KEY, + file, + newFileKey, + DOWNLOAD_CONDITIONS, + TRAFFIC_TAG, + /*extraHttpHeaders = */ ImmutableList.of()) + .get()); + assertThat(ex).hasCauseThat().isInstanceOf(DownloadException.class); + assertThat(ex).hasMessageThat().contains("SHARED_FILE_NOT_FOUND_ERROR"); + + verifyNoInteractions(mockDownloader); + } + + @Test + public void testStartDownload_newFile() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + Uri fileUri = sfm.getOnDeviceUri(newFileKey).get(); + when(fileGroupsMetadata.read(GROUP_KEY)).thenReturn(Futures.immediateFuture(FILE_GROUP)); + when(mockDownloader.startDownloading( + eq(GROUP_KEY), + eq(VERSION_NUMBER), + eq(BUILD_ID), + eq(fileUri), + eq(file.getUrlToDownload()), + eq(file.getByteSize()), + eq(DOWNLOAD_CONDITIONS), + isA(DownloaderCallbackImpl.class), + anyInt(), + anyList())) + .thenReturn(Futures.immediateFuture(null)); + + sfm.startDownload( + GROUP_KEY, + file, newFileKey, DOWNLOAD_CONDITIONS, TRAFFIC_TAG, /* extraHttpHeaders = */ ImmutableList.of()) - .get()); - assertThat(ex).hasCauseThat().isInstanceOf(DownloadException.class); - DownloadException dex = (DownloadException) ex.getCause(); - assertThat(dex.getDownloadResultCode()) - .isEqualTo(DownloadResultCode.INVALID_INLINE_FILE_URL_SCHEME); - } - -// TODO: (b/239218521) Test will be ready once mockto v4 is available -// @Test -// public void testStartDownload_unsubscribedFile() { -// DataFile file = MddTestUtil.createDataFile("fileId", 0); -// NewFileKey newFileKey = -// SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - -// ExecutionException ex = -// Assert.assertThrows( -// ExecutionException.class, -// () -> -// sfm.startDownload( -// GROUP_KEY, -// file, -// newFileKey, -// DOWNLOAD_CONDITIONS, -// TRAFFIC_TAG, -// /*extraHttpHeaders = */ ImmutableList.of()) -// .get()); -// assertThat(ex).hasCauseThat().isInstanceOf(DownloadException.class); -// assertThat(ex).hasMessageThat().contains("SHARED_FILE_NOT_FOUND_ERROR"); - -// verifyNoInteractions(mockDownloader); -// } - - @Test - public void testStartDownload_newFile() throws Exception { - DataFile file = MddTestUtil.createDataFile("fileId", 0); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - Uri fileUri = sfm.getOnDeviceUri(newFileKey).get(); - when(fileGroupsMetadata.read(GROUP_KEY)).thenReturn(Futures.immediateFuture(FILE_GROUP)); - when(mockDownloader.startDownloading( - eq(GROUP_KEY), - eq(VERSION_NUMBER), - eq(BUILD_ID), - eq(fileUri), - eq(file.getUrlToDownload()), - eq(file.getByteSize()), - eq(DOWNLOAD_CONDITIONS), - isA(DownloaderCallbackImpl.class), - anyInt(), - anyList())) - .thenReturn(Futures.immediateFuture(null)); - - sfm.startDownload( - GROUP_KEY, - file, - newFileKey, - DOWNLOAD_CONDITIONS, - TRAFFIC_TAG, - /* extraHttpHeaders = */ ImmutableList.of()) - .get(); - - SharedFile sharedFile = sharedFilesMetadata.read(newFileKey).get(); - assertThat(sharedFile.getFileStatus()).isEqualTo(FileStatus.DOWNLOAD_IN_PROGRESS); - } - -// TODO: (b/239218521) Test will be ready once mockto v4 is available -// @Test -// public void testStartDownload_downloadedFile() throws Exception { -// DataFile file = MddTestUtil.createDataFile("fileId", 0); -// NewFileKey newFileKey = -// SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - -// assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); -// File onDeviceFile = simulateDownload(file, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); -// changeFileStatusAs(newFileKey, FileStatus.DOWNLOAD_COMPLETE); - -// // The file is already downloaded, so we should just return DOWNLOADED. -// sfm.startDownload( -// GROUP_KEY, -// file, -// newFileKey, -// DOWNLOAD_CONDITIONS, -// TRAFFIC_TAG, -// /* extraHttpHeaders = */ ImmutableList.of()) -// .get(); -// onDeviceFile.delete(); - -// verify(mockDownloadMonitor).notifyCurrentFileSize(TEST_GROUP, file.getByteSize()); -// verifyNoInteractions(mockDownloader); -// } - -// TODO: (b/239218521) Test will be ready once mockto v4 is available -// @Test -// public void testVerifyDownload_nonExistentFile() throws Exception { -// DataFile file = MddTestUtil.createDataFile("fileId", 0); -// NewFileKey newFileKey = -// SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - -// ExecutionException ex = -// Assert.assertThrows(ExecutionException.class, () -> sfm.getFileStatus(newFileKey).get()); -// assertThat(ex).hasCauseThat().isInstanceOf(SharedFileMissingException.class); -// ex = Assert.assertThrows(ExecutionException.class, () -> sfm.getOnDeviceUri(newFileKey).get()); -// assertThat(ex).hasCauseThat().isInstanceOf(SharedFileMissingException.class); - -// verifyNoInteractions(mockDownloader); -// } - - @Test - public void testVerifyDownload_fileDownloaded() throws Exception { - DataFile file = MddTestUtil.createDataFile("fileId", 0); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - simulateDownload(file, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); - changeFileStatusAs(newFileKey, FileStatus.DOWNLOAD_COMPLETE); - - // VerifyDownload should update the onDeviceUri fields for storedFile. - assertThat(sfm.getFileStatus(newFileKey).get()).isEqualTo(FileStatus.DOWNLOAD_COMPLETE); - } - -// TODO: (b/239218521) Test will be ready once mockto v4 is available -// @Test -// public void testVerifyDownload_downloadNotAttempted() throws Exception { -// DataFile file = MddTestUtil.createDataFile("fileId", 0); -// NewFileKey newFileKey = -// SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - -// assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - -// assertThat(sfm.getFileStatus(newFileKey).get()).isEqualTo(FileStatus.SUBSCRIBED); - -// // getOnDeviceUri will populate the onDeviceUri even download was not attempted. -// assertThat(sfm.getOnDeviceUri(newFileKey).toString()).isNotEmpty(); - -// verifyNoInteractions(mockDownloader); -// } - -// TODO: (b/239218521) Test will be ready once mockto v4 is available -// @Test -// public void testVerifyDownload_alreadyDownloaded() throws Exception { -// DataFile file = MddTestUtil.createDataFile("fileId", 0); -// NewFileKey newFileKey = -// SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - -// assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); -// File onDeviceFile = simulateDownload(file, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); -// changeFileStatusAs(newFileKey, FileStatus.DOWNLOAD_COMPLETE); - -// assertThat(sfm.getFileStatus(newFileKey).get()).isEqualTo(FileStatus.DOWNLOAD_COMPLETE); -// assertThat(sfm.getOnDeviceUri(newFileKey).get()) -// .isEqualTo(AndroidUri.builder(context).fromFile(onDeviceFile).build()); - -// onDeviceFile.delete(); -// verifyNoInteractions(mockDownloader); -// } - - @Test - public void findNoDeltaFile_withNoBaseFileOnDevice() throws Exception { - DataFile file = MddTestUtil.createDataFileWithDeltaFile("fileId", 0, 3); - assertThat( - sfm.findFirstDeltaFileWithBaseFileDownloaded(file, AllowedReaders.ALL_GOOGLE_APPS) - .get()) - .isNull(); - } - - @Test - public void findExpectedDeltaFile_withDifferentReaderBaseFile() throws Exception { - DataFile file = MddTestUtil.createDataFileWithDeltaFile("fileId", 0, 3); - markBaseFileDownloaded( - file.getDeltaFile(1).getBaseFile().getChecksum(), AllowedReaders.ALL_GOOGLE_APPS); - assertThat( - sfm.findFirstDeltaFileWithBaseFileDownloaded( - file, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) - .get()) - .isNull(); - } - - @Test - public void findNoDeltaFile_whenDecoderNotSupported() throws Exception { - deltaDecoder = - Optional.of( - new DeltaDecoder() { - @Override - public void decode(Uri baseUri, Uri deltaUri, Uri targetUri) { - throw new UnsupportedOperationException("No delta decoder provided."); - } - - @Override - public DiffDecoder getDecoderName() { - return DiffDecoder.UNSPECIFIED; - } - }); - sfm = - new SharedFileManager( - context, - mockSilentFeedback, - sharedFilesMetadata, - fileStorage, - mockDownloader, - deltaDecoder, - Optional.of(mockDownloadMonitor), - eventLogger, - flags, - fileGroupsMetadata, - Optional.absent(), - CONTROL_EXECUTOR); - - DataFile file = MddTestUtil.createDataFileWithDeltaFile("fileId", 0, 3); - markBaseFileDownloaded( - file.getDeltaFile(1).getBaseFile().getChecksum(), AllowedReaders.ALL_GOOGLE_APPS); - DeltaFile deltaFile = - sfm.findFirstDeltaFileWithBaseFileDownloaded(file, AllowedReaders.ALL_GOOGLE_APPS).get(); - assertThat(deltaFile).isNull(); - } - - private void markBaseFileDownloaded(String checksum, AllowedReaders allowedReaders) - throws Exception { - NewFileKey fileKey = - NewFileKey.newBuilder().setChecksum(checksum).setAllowedReaders(allowedReaders).build(); - assertThat(sfm.reserveFileEntry(fileKey).get()).isTrue(); - changeFileStatusAs(fileKey, FileStatus.DOWNLOAD_COMPLETE); - } - - @Test - public void testClear() throws Exception { - // Create two files, one downloaded and the other currently being downloaded. - DataFile downloadedFile = MddTestUtil.createDataFile("file", 0); - DataFile registeredFile = MddTestUtil.createDataFile("registered-file", 0); - - NewFileKey downloadedKey = - SharedFilesMetadata.createKeyFromDataFile(downloadedFile, AllowedReaders.ALL_GOOGLE_APPS); - NewFileKey registeredKey = - SharedFilesMetadata.createKeyFromDataFile(registeredFile, AllowedReaders.ALL_GOOGLE_APPS); - - assertThat(sfm.reserveFileEntry(downloadedKey).get()).isTrue(); - File onDevicePublicFile = - simulateDownload(downloadedFile, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); - changeFileStatusAs(downloadedKey, FileStatus.DOWNLOAD_COMPLETE); - - assertThat(sfm.reserveFileEntry(registeredKey).get()).isTrue(); - - assertThat(sfm.getOnDeviceUri(downloadedKey).get()) - .isEqualTo(AndroidUri.builder(context).fromFile(onDevicePublicFile).build()); - assertThat(onDevicePublicFile.exists()).isTrue(); - - // Clear should delete all files in our directories. - sfm.clear().get(); - - assertThat(onDevicePublicFile.exists()).isFalse(); - } - - @Test - public void testClear_sdkLessthanR() throws Exception { - // Set scenario: SDK < R, enableAndroidFileSharing flag ON - ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.Q); - - // Create two files, one downloaded and the other currently being downloaded. - DataFile downloadedFile = MddTestUtil.createDataFile("file", 0); - DataFile registeredFile = MddTestUtil.createDataFile("registered-file", 0); - - NewFileKey downloadedKey = - SharedFilesMetadata.createKeyFromDataFile(downloadedFile, AllowedReaders.ALL_GOOGLE_APPS); - NewFileKey registeredKey = - SharedFilesMetadata.createKeyFromDataFile(registeredFile, AllowedReaders.ALL_GOOGLE_APPS); - - assertThat(sfm.reserveFileEntry(downloadedKey).get()).isTrue(); - File onDevicePublicFile = - simulateDownload(downloadedFile, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); - changeFileStatusAs(downloadedKey, FileStatus.DOWNLOAD_COMPLETE); - - assertThat(sfm.reserveFileEntry(registeredKey).get()).isTrue(); - - assertThat(sfm.getOnDeviceUri(downloadedKey).get()) - .isEqualTo(AndroidUri.builder(context).fromFile(onDevicePublicFile).build()); - assertThat(onDevicePublicFile.exists()).isTrue(); - - // Clear should delete all files in our directories. - sfm.clear().get(); - - assertThat(onDevicePublicFile.exists()).isFalse(); - verify(mockBackend, never()).deleteFile(any()); - verify(eventLogger, never()).logEventSampled(0); - } - - @Test - public void testClear_withAndroidSharedFiles() throws Exception { - // Set scenario: SDK >= R - ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.R); - - // Create three files, one downloaded, the other currently being downloaded and one shared with - // the Android Blob Sharing Service. - DataFile downloadedFile = MddTestUtil.createDataFile("file", /* fileIndex = */ 0); - DataFile registeredFile = MddTestUtil.createDataFile("registered-file", /* fileIndex = */ 1); - DataFile sharedFile = MddTestUtil.createSharedDataFile("shared-file", /* fileIndex = */ 2); - - NewFileKey downloadedKey = - SharedFilesMetadata.createKeyFromDataFile(downloadedFile, AllowedReaders.ALL_GOOGLE_APPS); - NewFileKey registeredKey = - SharedFilesMetadata.createKeyFromDataFile(registeredFile, AllowedReaders.ALL_GOOGLE_APPS); - NewFileKey sharedFileKey = - SharedFilesMetadata.createKeyFromDataFile(sharedFile, AllowedReaders.ALL_GOOGLE_APPS); - - assertThat(sfm.reserveFileEntry(downloadedKey).get()).isTrue(); - File onDevicePublicFile = - simulateDownload(downloadedFile, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); - changeFileStatusAs(downloadedKey, FileStatus.DOWNLOAD_COMPLETE); - - assertThat(sfm.reserveFileEntry(registeredKey).get()).isTrue(); - - assertThat(sfm.reserveFileEntry(sharedFileKey).get()).isTrue(); - assertThat( - sfm.setAndroidSharedDownloadedFileEntry( - sharedFileKey, - sharedFile.getAndroidSharingChecksum(), - FILE_GROUP_EXPIRATION_DATE_SECS) - .get()) - .isTrue(); - Uri allLeasesUri = DirectoryUtil.getBlobStoreAllLeasesUri(context); - - assertThat(sfm.getOnDeviceUri(downloadedKey).get()) - .isEqualTo(AndroidUri.builder(context).fromFile(onDevicePublicFile).build()); - assertThat(onDevicePublicFile.exists()).isTrue(); - - // Clear should delete all files in our directories. - sfm.clear().get(); - - assertThat(onDevicePublicFile.exists()).isFalse(); - verify(mockBackend).deleteFile(allLeasesUri); - - verify(eventLogger).logEventSampled(0); - } - -// TODO: (b/239218521) Test will be ready once mockto v4 is available -// @Test -// public void cancelDownload_onDownloadedFile() throws Exception { -// DataFile downloadedFile = MddTestUtil.createDataFile("downloaded-file", 0); -// NewFileKey downloadedKey = -// SharedFilesMetadata.createKeyFromDataFile(downloadedFile, AllowedReaders.ALL_GOOGLE_APPS); - -// assertThat(sfm.reserveFileEntry(downloadedKey).get()).isTrue(); -// changeFileStatusAs(downloadedKey, FileStatus.DOWNLOAD_COMPLETE); - -// // Calling cancelDownload on downloaded file is a no-op. -// sfm.cancelDownload(downloadedKey).get(); - -// verifyNoInteractions(mockDownloader); -// } - - @Test - public void cancelDownload_onRegisteredFile() throws Exception { - DataFile registeredFile = MddTestUtil.createDataFile("registered-file", 0); - NewFileKey registeredKey = - SharedFilesMetadata.createKeyFromDataFile(registeredFile, AllowedReaders.ALL_GOOGLE_APPS); - - assertThat(sfm.reserveFileEntry(registeredKey).get()).isTrue(); - - // Calling cancelDownload on registered file will stop the download. - sfm.cancelDownload(registeredKey).get(); - - SharedFile sharedFile = sharedFilesMetadata.read(registeredKey).get(); - assertThat(sharedFile).isNotNull(); - Uri onDeviceUri = - DirectoryUtil.getOnDeviceUri( - context, - registeredKey.getAllowedReaders(), - sharedFile.getFileName(), - registeredFile.getChecksum(), - mockSilentFeedback, - /* instanceId= */ Optional.absent(), - false); - verify(mockDownloader).stopDownloading(onDeviceUri); - } - - @Test - public void testGetSharedFile() throws Exception { - DataFile file = MddTestUtil.createDataFile("fileId", /* fileIndex = */ 0); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - - SharedFile sharedFile = sfm.getSharedFile(newFileKey).get(); - SharedFile expectedSharedFile = sharedFilesMetadata.read(newFileKey).get(); - - assertThat(sharedFile).isNotNull(); - assertThat(sharedFile).isEqualTo(expectedSharedFile); - } - - @Test - public void testGetSharedFile_nonExistentFile() throws Exception { - DataFile file = MddTestUtil.createDataFile("fileId", 0); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - - ExecutionException ex = - Assert.assertThrows(ExecutionException.class, () -> sfm.getSharedFile(newFileKey).get()); - assertThat(ex).hasCauseThat().isInstanceOf(SharedFileMissingException.class); - } - - @Test - public void testUpdateMaxExpirationDateSecs() throws Exception { - DataFile file = MddTestUtil.createDataFile("fileId", 0); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - SharedFile sharedFileBeforeUpdate = sharedFilesMetadata.read(newFileKey).get(); - SharedFile expectedSharedFileAfterUpdate = - SharedFile.newBuilder(sharedFileBeforeUpdate) - .setMaxExpirationDateSecs(FILE_GROUP_EXPIRATION_DATE_SECS) - .build(); - - assertThat(sharedFileBeforeUpdate).isNotNull(); - assertThat(sharedFileBeforeUpdate).isNotEqualTo(expectedSharedFileAfterUpdate); - - // updateMaxExpirationDateSecs updates maxExpirationDateSecs - assertThat(sfm.updateMaxExpirationDateSecs(newFileKey, FILE_GROUP_EXPIRATION_DATE_SECS).get()) - .isTrue(); - SharedFile sharedFileAfterUpdate = sharedFilesMetadata.read(newFileKey).get(); - assertThat(sharedFileAfterUpdate).isNotNull(); - assertThat(sharedFileAfterUpdate).isEqualTo(expectedSharedFileAfterUpdate); - - // updateMaxExpirationDateSecs doesn't update maxExpirationDateSecs - assertThat( - sfm.updateMaxExpirationDateSecs(newFileKey, FILE_GROUP_EXPIRATION_DATE_SECS - 1).get()) - .isTrue(); - SharedFile sharedFileAfterSecondUpdate = sharedFilesMetadata.read(newFileKey).get(); - assertThat(sharedFileAfterSecondUpdate).isNotNull(); - assertThat(sharedFileAfterSecondUpdate).isEqualTo(expectedSharedFileAfterUpdate); - } - - @Test - public void testUpdateMaxExpirationDateSecs_nonExistentFile() throws Exception { - DataFile file = MddTestUtil.createDataFile("fileId", 0); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - - ExecutionException ex = - Assert.assertThrows( - ExecutionException.class, - () -> - sfm.updateMaxExpirationDateSecs(newFileKey, FILE_GROUP_EXPIRATION_DATE_SECS).get()); - assertThat(ex).hasCauseThat().isInstanceOf(SharedFileMissingException.class); - } - - @Test - public void testSetAndroidSharedDownloadedFileEntry() throws Exception { - DataFile file = MddTestUtil.createSharedDataFile("fileId", 0); - SharedFile expectedSharedFileAfterUpdate = - SharedFile.newBuilder() - .setFileStatus(FileStatus.DOWNLOAD_COMPLETE) - .setFileName("android_shared_" + file.getAndroidSharingChecksum()) - .setAndroidShared(true) - .setMaxExpirationDateSecs(FILE_GROUP_EXPIRATION_DATE_SECS) - .setAndroidSharingChecksum(file.getAndroidSharingChecksum()) - .build(); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - - SharedFile sharedFile = sharedFilesMetadata.read(newFileKey).get(); - assertThat(sharedFile).isNotNull(); - assertThat(sharedFile).isNotEqualTo(expectedSharedFileAfterUpdate); - - assertThat( - sfm.setAndroidSharedDownloadedFileEntry( - newFileKey, file.getAndroidSharingChecksum(), FILE_GROUP_EXPIRATION_DATE_SECS) - .get()) - .isTrue(); - sharedFile = sharedFilesMetadata.read(newFileKey).get(); - assertThat(sharedFile).isNotNull(); - assertThat(sharedFile).isEqualTo(expectedSharedFileAfterUpdate); - } - - @Test - public void testOnDeviceUri() throws Exception { - DataFile file = MddTestUtil.createSharedDataFile("fileId", 0); - NewFileKey newFileKey = - SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); - - assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); - - File onDeviceFile = simulateDownload(file, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); - assertThat(sfm.getOnDeviceUri(newFileKey).get()) - .isEqualTo(AndroidUri.builder(context).fromFile(onDeviceFile).build()); - - assertThat( - sfm.setAndroidSharedDownloadedFileEntry( - newFileKey, file.getAndroidSharingChecksum(), FILE_GROUP_EXPIRATION_DATE_SECS) - .get()) - .isTrue(); - assertThat(sfm.getOnDeviceUri(newFileKey).get()) - .isEqualTo( - BlobUri.builder(context).setBlobParameters(file.getAndroidSharingChecksum()).build()); - } - - private File simulateDownload(DataFile dataFile, String fileName, AllowedReaders allowedReaders) - throws IOException { - File onDeviceFile; - if (allowedReaders == AllowedReaders.ALL_GOOGLE_APPS) { - onDeviceFile = new File(publicDirectory, fileName); - } else { - onDeviceFile = new File(privateDirectory, fileName); - } - FileOutputStream writer = new FileOutputStream(onDeviceFile); - byte[] bytes = new byte[dataFile.getByteSize()]; - writer.write(bytes); - writer.close(); - - return onDeviceFile; - } - - private void changeFileStatusAs(NewFileKey newFileKey, FileStatus fileStatus) - throws InterruptedException, ExecutionException { - synchronized (SharedFilesMetadata.class) { - SharedFile sharedFile = sharedFilesMetadata.read(newFileKey).get(); - sharedFile = sharedFile.toBuilder().setFileStatus(fileStatus).build(); - assertThat(sharedFilesMetadata.write(newFileKey, sharedFile).get()).isTrue(); - } - } - - private String getLastFileName() { - SharedPreferences sfmMetadata = - SharedPreferencesUtil.getSharedPreferences( - context, MDD_SHARED_FILE_MANAGER_METADATA, Optional.absent()); - long lastName = sfmMetadata.getLong(SharedFileManager.PREFS_KEY_NEXT_FILE_NAME, 1) - 1; - return SharedFileManager.FILE_NAME_PREFIX + lastName; - } + .get(); + + SharedFile sharedFile = sharedFilesMetadata.read(newFileKey).get(); + assertThat(sharedFile.getFileStatus()).isEqualTo(FileStatus.DOWNLOAD_IN_PROGRESS); + } + + @Test + public void testStartDownload_downloadedFile() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + File onDeviceFile = simulateDownload(file, getLastFileName(), + AllowedReaders.ALL_GOOGLE_APPS); + changeFileStatusAs(newFileKey, FileStatus.DOWNLOAD_COMPLETE); + + // The file is already downloaded, so we should just return DOWNLOADED. + sfm.startDownload( + GROUP_KEY, + file, + newFileKey, + DOWNLOAD_CONDITIONS, + TRAFFIC_TAG, + /* extraHttpHeaders = */ ImmutableList.of()) + .get(); + onDeviceFile.delete(); + + verify(mockDownloadMonitor).notifyCurrentFileSize(TEST_GROUP, file.getByteSize()); + verifyNoInteractions(mockDownloader); + } + + @Test + public void testVerifyDownload_nonExistentFile() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + ExecutionException ex = + Assert.assertThrows(ExecutionException.class, + () -> sfm.getFileStatus(newFileKey).get()); + assertThat(ex).hasCauseThat().isInstanceOf(SharedFileMissingException.class); + ex = Assert.assertThrows(ExecutionException.class, + () -> sfm.getOnDeviceUri(newFileKey).get()); + assertThat(ex).hasCauseThat().isInstanceOf(SharedFileMissingException.class); + + verifyNoInteractions(mockDownloader); + } + + @Test + public void testVerifyDownload_fileDownloaded() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + simulateDownload(file, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); + changeFileStatusAs(newFileKey, FileStatus.DOWNLOAD_COMPLETE); + + // VerifyDownload should update the onDeviceUri fields for storedFile. + assertThat(sfm.getFileStatus(newFileKey).get()).isEqualTo(FileStatus.DOWNLOAD_COMPLETE); + } + + @Test + public void testVerifyDownload_downloadNotAttempted() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + + assertThat(sfm.getFileStatus(newFileKey).get()).isEqualTo(FileStatus.SUBSCRIBED); + + // getOnDeviceUri will populate the onDeviceUri even download was not attempted. + assertThat(sfm.getOnDeviceUri(newFileKey).toString()).isNotEmpty(); + + verifyNoInteractions(mockDownloader); + } + + @Test + public void testVerifyDownload_alreadyDownloaded() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + File onDeviceFile = simulateDownload(file, getLastFileName(), + AllowedReaders.ALL_GOOGLE_APPS); + changeFileStatusAs(newFileKey, FileStatus.DOWNLOAD_COMPLETE); + + assertThat(sfm.getFileStatus(newFileKey).get()).isEqualTo(FileStatus.DOWNLOAD_COMPLETE); + assertThat(sfm.getOnDeviceUri(newFileKey).get()) + .isEqualTo(AndroidUri.builder(context).fromFile(onDeviceFile).build()); + + onDeviceFile.delete(); + verifyNoInteractions(mockDownloader); + } + + @Test + public void findNoDeltaFile_withNoBaseFileOnDevice() throws Exception { + DataFile file = MddTestUtil.createDataFileWithDeltaFile("fileId", 0, 3); + assertThat( + sfm.findFirstDeltaFileWithBaseFileDownloaded(file, AllowedReaders.ALL_GOOGLE_APPS) + .get()) + .isNull(); + } + + @Test + public void findExpectedDeltaFile_withDifferentReaderBaseFile() throws Exception { + DataFile file = MddTestUtil.createDataFileWithDeltaFile("fileId", 0, 3); + markBaseFileDownloaded( + file.getDeltaFile(1).getBaseFile().getChecksum(), AllowedReaders.ALL_GOOGLE_APPS); + assertThat( + sfm.findFirstDeltaFileWithBaseFileDownloaded( + file, AllowedReaders.ONLY_GOOGLE_PLAY_SERVICES) + .get()) + .isNull(); + } + + @Test + public void findNoDeltaFile_whenDecoderNotSupported() throws Exception { + deltaDecoder = + Optional.of( + new DeltaDecoder() { + @Override + public void decode(Uri baseUri, Uri deltaUri, Uri targetUri) { + throw new UnsupportedOperationException( + "No delta decoder provided."); + } + + @Override + public DiffDecoder getDecoderName() { + return DiffDecoder.UNSPECIFIED; + } + }); + sfm = + new SharedFileManager( + context, + mockSilentFeedback, + sharedFilesMetadata, + fileStorage, + mockDownloader, + deltaDecoder, + Optional.of(mockDownloadMonitor), + eventLogger, + flags, + fileGroupsMetadata, + Optional.absent(), + CONTROL_EXECUTOR); + + DataFile file = MddTestUtil.createDataFileWithDeltaFile("fileId", 0, 3); + markBaseFileDownloaded( + file.getDeltaFile(1).getBaseFile().getChecksum(), AllowedReaders.ALL_GOOGLE_APPS); + DeltaFile deltaFile = + sfm.findFirstDeltaFileWithBaseFileDownloaded(file, + AllowedReaders.ALL_GOOGLE_APPS).get(); + assertThat(deltaFile).isNull(); + } + + private void markBaseFileDownloaded(String checksum, AllowedReaders allowedReaders) + throws Exception { + NewFileKey fileKey = + NewFileKey.newBuilder().setChecksum(checksum).setAllowedReaders( + allowedReaders).build(); + assertThat(sfm.reserveFileEntry(fileKey).get()).isTrue(); + changeFileStatusAs(fileKey, FileStatus.DOWNLOAD_COMPLETE); + } + + @Test + public void testClear() throws Exception { + // Create two files, one downloaded and the other currently being downloaded. + DataFile downloadedFile = MddTestUtil.createDataFile("file", 0); + DataFile registeredFile = MddTestUtil.createDataFile("registered-file", 0); + + NewFileKey downloadedKey = + SharedFilesMetadata.createKeyFromDataFile(downloadedFile, + AllowedReaders.ALL_GOOGLE_APPS); + NewFileKey registeredKey = + SharedFilesMetadata.createKeyFromDataFile(registeredFile, + AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(downloadedKey).get()).isTrue(); + File onDevicePublicFile = + simulateDownload(downloadedFile, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); + changeFileStatusAs(downloadedKey, FileStatus.DOWNLOAD_COMPLETE); + + assertThat(sfm.reserveFileEntry(registeredKey).get()).isTrue(); + + assertThat(sfm.getOnDeviceUri(downloadedKey).get()) + .isEqualTo(AndroidUri.builder(context).fromFile(onDevicePublicFile).build()); + assertThat(onDevicePublicFile.exists()).isTrue(); + + // Clear should delete all files in our directories. + sfm.clear().get(); + + assertThat(onDevicePublicFile.exists()).isFalse(); + } + + @Test + public void testClear_sdkLessthanR() throws Exception { + // Set scenario: SDK < R, enableAndroidFileSharing flag ON + ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.Q); + + // Create two files, one downloaded and the other currently being downloaded. + DataFile downloadedFile = MddTestUtil.createDataFile("file", 0); + DataFile registeredFile = MddTestUtil.createDataFile("registered-file", 0); + + NewFileKey downloadedKey = + SharedFilesMetadata.createKeyFromDataFile(downloadedFile, + AllowedReaders.ALL_GOOGLE_APPS); + NewFileKey registeredKey = + SharedFilesMetadata.createKeyFromDataFile(registeredFile, + AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(downloadedKey).get()).isTrue(); + File onDevicePublicFile = + simulateDownload(downloadedFile, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); + changeFileStatusAs(downloadedKey, FileStatus.DOWNLOAD_COMPLETE); + + assertThat(sfm.reserveFileEntry(registeredKey).get()).isTrue(); + + assertThat(sfm.getOnDeviceUri(downloadedKey).get()) + .isEqualTo(AndroidUri.builder(context).fromFile(onDevicePublicFile).build()); + assertThat(onDevicePublicFile.exists()).isTrue(); + + // Clear should delete all files in our directories. + sfm.clear().get(); + + assertThat(onDevicePublicFile.exists()).isFalse(); + verify(mockBackend, never()).deleteFile(any()); + verify(eventLogger, never()).logEventSampled(0); + } + + @Test + public void testClear_withAndroidSharedFiles() throws Exception { + // Set scenario: SDK >= R + ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.R); + + // Create three files, one downloaded, the other currently being downloaded and one + // shared with + // the Android Blob Sharing Service. + DataFile downloadedFile = MddTestUtil.createDataFile("file", /* fileIndex = */ 0); + DataFile registeredFile = MddTestUtil.createDataFile("registered-file", /* fileIndex = */ + 1); + DataFile sharedFile = MddTestUtil.createSharedDataFile("shared-file", /* fileIndex = */ 2); + + NewFileKey downloadedKey = + SharedFilesMetadata.createKeyFromDataFile(downloadedFile, + AllowedReaders.ALL_GOOGLE_APPS); + NewFileKey registeredKey = + SharedFilesMetadata.createKeyFromDataFile(registeredFile, + AllowedReaders.ALL_GOOGLE_APPS); + NewFileKey sharedFileKey = + SharedFilesMetadata.createKeyFromDataFile(sharedFile, + AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(downloadedKey).get()).isTrue(); + File onDevicePublicFile = + simulateDownload(downloadedFile, getLastFileName(), AllowedReaders.ALL_GOOGLE_APPS); + changeFileStatusAs(downloadedKey, FileStatus.DOWNLOAD_COMPLETE); + + assertThat(sfm.reserveFileEntry(registeredKey).get()).isTrue(); + + assertThat(sfm.reserveFileEntry(sharedFileKey).get()).isTrue(); + assertThat( + sfm.setAndroidSharedDownloadedFileEntry( + sharedFileKey, + sharedFile.getAndroidSharingChecksum(), + FILE_GROUP_EXPIRATION_DATE_SECS) + .get()) + .isTrue(); + Uri allLeasesUri = DirectoryUtil.getBlobStoreAllLeasesUri(context); + + assertThat(sfm.getOnDeviceUri(downloadedKey).get()) + .isEqualTo(AndroidUri.builder(context).fromFile(onDevicePublicFile).build()); + assertThat(onDevicePublicFile.exists()).isTrue(); + + // Clear should delete all files in our directories. + sfm.clear().get(); + + assertThat(onDevicePublicFile.exists()).isFalse(); + verify(mockBackend).deleteFile(allLeasesUri); + + verify(eventLogger).logEventSampled(0); + } + + @Test + public void cancelDownload_onDownloadedFile() throws Exception { + DataFile downloadedFile = MddTestUtil.createDataFile("downloaded-file", 0); + NewFileKey downloadedKey = + SharedFilesMetadata.createKeyFromDataFile(downloadedFile, + AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(downloadedKey).get()).isTrue(); + changeFileStatusAs(downloadedKey, FileStatus.DOWNLOAD_COMPLETE); + + // Calling cancelDownload on downloaded file is a no-op. + sfm.cancelDownload(downloadedKey).get(); + + verifyNoInteractions(mockDownloader); + } + + @Test + public void cancelDownload_onRegisteredFile() throws Exception { + DataFile registeredFile = MddTestUtil.createDataFile("registered-file", 0); + NewFileKey registeredKey = + SharedFilesMetadata.createKeyFromDataFile(registeredFile, + AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(registeredKey).get()).isTrue(); + + // Calling cancelDownload on registered file will stop the download. + sfm.cancelDownload(registeredKey).get(); + + SharedFile sharedFile = sharedFilesMetadata.read(registeredKey).get(); + assertThat(sharedFile).isNotNull(); + Uri onDeviceUri = + DirectoryUtil.getOnDeviceUri( + context, + registeredKey.getAllowedReaders(), + sharedFile.getFileName(), + registeredFile.getChecksum(), + mockSilentFeedback, + /* instanceId= */ Optional.absent(), + false); + verify(mockDownloader).stopDownloading(onDeviceUri); + } + + @Test + public void testGetSharedFile() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", /* fileIndex = */ 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + + SharedFile sharedFile = sfm.getSharedFile(newFileKey).get(); + SharedFile expectedSharedFile = sharedFilesMetadata.read(newFileKey).get(); + + assertThat(sharedFile).isNotNull(); + assertThat(sharedFile).isEqualTo(expectedSharedFile); + } + + @Test + public void testGetSharedFile_nonExistentFile() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + ExecutionException ex = + Assert.assertThrows(ExecutionException.class, + () -> sfm.getSharedFile(newFileKey).get()); + assertThat(ex).hasCauseThat().isInstanceOf(SharedFileMissingException.class); + } + + @Test + public void testUpdateMaxExpirationDateSecs() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + SharedFile sharedFileBeforeUpdate = sharedFilesMetadata.read(newFileKey).get(); + SharedFile expectedSharedFileAfterUpdate = + SharedFile.newBuilder(sharedFileBeforeUpdate) + .setMaxExpirationDateSecs(FILE_GROUP_EXPIRATION_DATE_SECS) + .build(); + + assertThat(sharedFileBeforeUpdate).isNotNull(); + assertThat(sharedFileBeforeUpdate).isNotEqualTo(expectedSharedFileAfterUpdate); + + // updateMaxExpirationDateSecs updates maxExpirationDateSecs + assertThat( + sfm.updateMaxExpirationDateSecs(newFileKey, FILE_GROUP_EXPIRATION_DATE_SECS).get()) + .isTrue(); + SharedFile sharedFileAfterUpdate = sharedFilesMetadata.read(newFileKey).get(); + assertThat(sharedFileAfterUpdate).isNotNull(); + assertThat(sharedFileAfterUpdate).isEqualTo(expectedSharedFileAfterUpdate); + + // updateMaxExpirationDateSecs doesn't update maxExpirationDateSecs + assertThat( + sfm.updateMaxExpirationDateSecs(newFileKey, + FILE_GROUP_EXPIRATION_DATE_SECS - 1).get()) + .isTrue(); + SharedFile sharedFileAfterSecondUpdate = sharedFilesMetadata.read(newFileKey).get(); + assertThat(sharedFileAfterSecondUpdate).isNotNull(); + assertThat(sharedFileAfterSecondUpdate).isEqualTo(expectedSharedFileAfterUpdate); + } + + @Test + public void testUpdateMaxExpirationDateSecs_nonExistentFile() throws Exception { + DataFile file = MddTestUtil.createDataFile("fileId", 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + ExecutionException ex = + Assert.assertThrows( + ExecutionException.class, + () -> + sfm.updateMaxExpirationDateSecs(newFileKey, + FILE_GROUP_EXPIRATION_DATE_SECS).get()); + assertThat(ex).hasCauseThat().isInstanceOf(SharedFileMissingException.class); + } + + @Test + public void testSetAndroidSharedDownloadedFileEntry() throws Exception { + DataFile file = MddTestUtil.createSharedDataFile("fileId", 0); + SharedFile expectedSharedFileAfterUpdate = + SharedFile.newBuilder() + .setFileStatus(FileStatus.DOWNLOAD_COMPLETE) + .setFileName("android_shared_" + file.getAndroidSharingChecksum()) + .setAndroidShared(true) + .setMaxExpirationDateSecs(FILE_GROUP_EXPIRATION_DATE_SECS) + .setAndroidSharingChecksum(file.getAndroidSharingChecksum()) + .build(); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + + SharedFile sharedFile = sharedFilesMetadata.read(newFileKey).get(); + assertThat(sharedFile).isNotNull(); + assertThat(sharedFile).isNotEqualTo(expectedSharedFileAfterUpdate); + + assertThat( + sfm.setAndroidSharedDownloadedFileEntry( + newFileKey, file.getAndroidSharingChecksum(), + FILE_GROUP_EXPIRATION_DATE_SECS) + .get()) + .isTrue(); + sharedFile = sharedFilesMetadata.read(newFileKey).get(); + assertThat(sharedFile).isNotNull(); + assertThat(sharedFile).isEqualTo(expectedSharedFileAfterUpdate); + } + + @Test + public void testOnDeviceUri() throws Exception { + DataFile file = MddTestUtil.createSharedDataFile("fileId", 0); + NewFileKey newFileKey = + SharedFilesMetadata.createKeyFromDataFile(file, AllowedReaders.ALL_GOOGLE_APPS); + + assertThat(sfm.reserveFileEntry(newFileKey).get()).isTrue(); + + File onDeviceFile = simulateDownload(file, getLastFileName(), + AllowedReaders.ALL_GOOGLE_APPS); + assertThat(sfm.getOnDeviceUri(newFileKey).get()) + .isEqualTo(AndroidUri.builder(context).fromFile(onDeviceFile).build()); + + assertThat( + sfm.setAndroidSharedDownloadedFileEntry( + newFileKey, file.getAndroidSharingChecksum(), + FILE_GROUP_EXPIRATION_DATE_SECS) + .get()) + .isTrue(); + assertThat(sfm.getOnDeviceUri(newFileKey).get()) + .isEqualTo( + BlobUri.builder(context).setBlobParameters( + file.getAndroidSharingChecksum()).build()); + } + + private File simulateDownload(DataFile dataFile, String fileName, AllowedReaders allowedReaders) + throws IOException { + File onDeviceFile; + if (allowedReaders == AllowedReaders.ALL_GOOGLE_APPS) { + onDeviceFile = new File(publicDirectory, fileName); + } else { + onDeviceFile = new File(privateDirectory, fileName); + } + FileOutputStream writer = new FileOutputStream(onDeviceFile); + byte[] bytes = new byte[dataFile.getByteSize()]; + writer.write(bytes); + writer.close(); + + return onDeviceFile; + } + + private void changeFileStatusAs(NewFileKey newFileKey, FileStatus fileStatus) + throws InterruptedException, ExecutionException { + synchronized (SharedFilesMetadata.class) { + SharedFile sharedFile = sharedFilesMetadata.read(newFileKey).get(); + sharedFile = sharedFile.toBuilder().setFileStatus(fileStatus).build(); + assertThat(sharedFilesMetadata.write(newFileKey, sharedFile).get()).isTrue(); + } + } + + private String getLastFileName() { + SharedPreferences sfmMetadata = + SharedPreferencesUtil.getSharedPreferences( + context, MDD_SHARED_FILE_MANAGER_METADATA, Optional.absent()); + long lastName = sfmMetadata.getLong(SharedFileManager.PREFS_KEY_NEXT_FILE_NAME, 1) - 1; + return SharedFileManager.FILE_NAME_PREFIX + lastName; + } } diff --git a/javatests/com/google/android/libraries/mobiledatadownload/internal/logging/MddEventLoggerTest.java b/javatests/com/google/android/libraries/mobiledatadownload/internal/logging/MddEventLoggerTest.java index dd1f027..d31534a 100644 --- a/javatests/com/google/android/libraries/mobiledatadownload/internal/logging/MddEventLoggerTest.java +++ b/javatests/com/google/android/libraries/mobiledatadownload/internal/logging/MddEventLoggerTest.java @@ -18,14 +18,18 @@ package com.google.android.libraries.mobiledatadownload.internal.logging; import static com.google.common.util.concurrent.Futures.immediateFuture; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import android.content.Context; import android.content.SharedPreferences; + import androidx.test.core.app.ApplicationProvider; + import com.google.android.libraries.mobiledatadownload.Logger; import com.google.android.libraries.mobiledatadownload.internal.logging.EventLogger.FileGroupStatusWithDetails; import com.google.android.libraries.mobiledatadownload.testing.FakeTimeSource; @@ -40,8 +44,7 @@ import com.google.mobiledatadownload.LogProto.MddDeviceInfo; import com.google.mobiledatadownload.LogProto.MddFileGroupStatus; import com.google.mobiledatadownload.LogProto.MddLogData; import com.google.mobiledatadownload.LogProto.StableSamplingInfo; -import java.security.SecureRandom; -import java.util.Random; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -51,16 +54,21 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; +import java.security.SecureRandom; +import java.util.Random; + @RunWith(RobolectricTestRunner.class) public class MddEventLoggerTest { - @Rule public final MockitoRule mocks = MockitoJUnit.rule(); + @Rule + public final MockitoRule mocks = MockitoJUnit.rule(); private static final int SOME_MODULE_VERSION = 42; private static final int SAMPLING_ALWAYS = 1; private static final int SAMPLING_NEVER = 0; - @Mock private Logger mockLogger; + @Mock + private Logger mockLogger; private MddEventLogger mddEventLogger; private final Context context = ApplicationProvider.getApplicationContext(); @@ -79,7 +87,8 @@ public class MddEventLoggerTest { flags); mddEventLogger.setLoggingStateStore( SharedPreferencesLoggingState.create( - () -> loggingStateSharedPrefs, new FakeTimeSource(), directExecutor(), new Random(0))); + () -> loggingStateSharedPrefs, new FakeTimeSource(), directExecutor(), + new Random(0))); } private MddLogData.Builder newLogDataBuilderWithClientInfo() { @@ -105,31 +114,31 @@ public class MddEventLoggerTest { assertTrue(LogUtil.shouldSampleInterval(1)); } -// TODO: (b/239218521) Test will be ready once mockto v4 is available -// @Test -// public void testLogMddEvents_noLog() throws Exception { -// overrideDefaultSampleInterval(SAMPLING_NEVER); - -// DataDownloadFileGroupStats fileGroupStats = -// DataDownloadFileGroupStats.newBuilder() -// .setFileGroupName("fileGroup") -// .setFileGroupVersionNumber(1) -// .setBuildId(123) -// .setVariantId("testVariant") -// .build(); -// MddFileGroupStatus fileGroupStatus = -// MddFileGroupStatus.newBuilder() -// .setFileGroupDownloadStatus(MddFileGroupDownloadStatus.Code.COMPLETE) -// .build(); -// FileGroupStatusWithDetails fileGroupStatusWithDetails = -// FileGroupStatusWithDetails.create(fileGroupStatus, fileGroupStats); - -// mddEventLogger -// .logMddFileGroupStats(() -> immediateFuture(ImmutableList.of(fileGroupStatusWithDetails))) -// .get(); - -// verifyNoInteractions(mockLogger); -// } + @Test + public void testLogMddEvents_noLog() throws Exception { + overrideDefaultSampleInterval(SAMPLING_NEVER); + + DataDownloadFileGroupStats fileGroupStats = + DataDownloadFileGroupStats.newBuilder() + .setFileGroupName("fileGroup") + .setFileGroupVersionNumber(1) + .setBuildId(123) + .setVariantId("testVariant") + .build(); + MddFileGroupStatus fileGroupStatus = + MddFileGroupStatus.newBuilder() + .setFileGroupDownloadStatus(MddFileGroupDownloadStatus.Code.COMPLETE) + .build(); + FileGroupStatusWithDetails fileGroupStatusWithDetails = + FileGroupStatusWithDetails.create(fileGroupStatus, fileGroupStats); + + mddEventLogger + .logMddFileGroupStats( + () -> immediateFuture(ImmutableList.of(fileGroupStatusWithDetails))) + .get(); + + verifyNoInteractions(mockLogger); + } @Test public void testLogMddEvents() throws Exception { @@ -159,11 +168,13 @@ public class MddEventLoggerTest { .build(); mddEventLogger - .logMddFileGroupStats(() -> immediateFuture(ImmutableList.of(fileGroupStatusWithDetails))) + .logMddFileGroupStats( + () -> immediateFuture(ImmutableList.of(fileGroupStatusWithDetails))) .get(); verify(mockLogger) - .log(eq(expectedData), eq(MddClientEvent.Code.DATA_DOWNLOAD_FILE_GROUP_STATUS_VALUE)); + .log(eq(expectedData), + eq(MddClientEvent.Code.DATA_DOWNLOAD_FILE_GROUP_STATUS_VALUE)); } private void overrideDefaultSampleInterval(int sampleInterval) { |