| /* |
| * Copyright 2022 Google LLC |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| 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; |
| import static org.mockito.ArgumentMatchers.eq; |
| 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; |
| import com.google.android.libraries.mobiledatadownload.SilentFeedback; |
| import com.google.android.libraries.mobiledatadownload.delta.DeltaDecoder; |
| import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage; |
| import com.google.android.libraries.mobiledatadownload.file.backends.AndroidFileBackend; |
| import com.google.android.libraries.mobiledatadownload.file.backends.AndroidUri; |
| import com.google.android.libraries.mobiledatadownload.file.backends.BlobUri; |
| import com.google.android.libraries.mobiledatadownload.file.spi.Backend; |
| import com.google.android.libraries.mobiledatadownload.file.transforms.CompressTransform; |
| import com.google.android.libraries.mobiledatadownload.internal.Migrations.FileKeyVersion; |
| import com.google.android.libraries.mobiledatadownload.internal.downloader.DownloaderCallbackImpl; |
| import com.google.android.libraries.mobiledatadownload.internal.downloader.MddFileDownloader; |
| import com.google.android.libraries.mobiledatadownload.internal.logging.EventLogger; |
| import com.google.android.libraries.mobiledatadownload.internal.util.DirectoryUtil; |
| import com.google.android.libraries.mobiledatadownload.internal.util.FileGroupUtil; |
| import com.google.android.libraries.mobiledatadownload.internal.util.SharedPreferencesUtil; |
| import com.google.android.libraries.mobiledatadownload.monitor.DownloadProgressMonitor; |
| import com.google.android.libraries.mobiledatadownload.testing.TestFlags; |
| import com.google.common.base.Optional; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.util.concurrent.Futures; |
| import com.google.common.util.concurrent.MoreExecutors; |
| import com.google.mobiledatadownload.internal.MetadataProto.DataFile; |
| import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupInternal; |
| import com.google.mobiledatadownload.internal.MetadataProto.DataFileGroupInternal.AllowedReaders; |
| import com.google.mobiledatadownload.internal.MetadataProto.DeltaFile; |
| import com.google.mobiledatadownload.internal.MetadataProto.DeltaFile.DiffDecoder; |
| import com.google.mobiledatadownload.internal.MetadataProto.DownloadConditions; |
| 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 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; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.mockito.Mock; |
| import org.mockito.junit.MockitoJUnit; |
| import org.mockito.junit.MockitoRule; |
| import org.robolectric.ParameterizedRobolectricTestRunner; |
| import org.robolectric.ParameterizedRobolectricTestRunner.Parameter; |
| import org.robolectric.ParameterizedRobolectricTestRunner.Parameters; |
| import org.robolectric.annotation.Config; |
| import org.robolectric.util.ReflectionHelpers; |
| |
| @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 = |
| 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, |
| 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(); |
| |
| 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; |
| } |
| } |