Test restoring deleted row IDs on create & rename
Create & rename can restore row IDs corresponding to deleted path. Added
tests to verify we restored deleted row IDs.
Test: atest FuseDaemonHostTest#testCreateCanRestoreDeletedRowId
Test: atest FuseDaemonHostTest#testRenameCanRestoreDeletedRowId
Bug: 151076202
Change-Id: I56bc5e4bfa5a7583277a5b7fbae7bbaf912edca0
diff --git a/tests/jni/FuseDaemonTest/host/src/com/android/tests/fused/host/FuseDaemonHostTest.java b/tests/jni/FuseDaemonTest/host/src/com/android/tests/fused/host/FuseDaemonHostTest.java
index 9d8a1a0..a69cfc7 100644
--- a/tests/jni/FuseDaemonTest/host/src/com/android/tests/fused/host/FuseDaemonHostTest.java
+++ b/tests/jni/FuseDaemonTest/host/src/com/android/tests/fused/host/FuseDaemonHostTest.java
@@ -270,4 +270,14 @@
public void testSystemGalleryCanRenameImageAndVideoDirs() throws Exception {
runDeviceTest("testSystemGalleryCanRenameImageAndVideoDirs");
}
+
+ @Test
+ public void testCreateCanRestoreDeletedRowId() throws Exception {
+ runDeviceTest("testCreateCanRestoreDeletedRowId");
+ }
+
+ @Test
+ public void testRenameCanRestoreDeletedRowId() throws Exception {
+ runDeviceTest("testRenameCanRestoreDeletedRowId");
+ }
}
diff --git a/tests/jni/FuseDaemonTest/src/com/android/tests/fused/FilePathAccessTest.java b/tests/jni/FuseDaemonTest/src/com/android/tests/fused/FilePathAccessTest.java
index b2a8941..5af699b 100644
--- a/tests/jni/FuseDaemonTest/src/com/android/tests/fused/FilePathAccessTest.java
+++ b/tests/jni/FuseDaemonTest/src/com/android/tests/fused/FilePathAccessTest.java
@@ -88,6 +88,8 @@
import com.android.cts.install.lib.TestApp;
import com.android.tests.fused.lib.ReaddirTestHelper;
+import com.google.common.io.Files;
+
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -95,6 +97,7 @@
import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -678,6 +681,7 @@
assertThat(listAs(TEST_APP_A, EXTERNAL_MEDIA_DIR.getPath())).containsExactly(videoFileName);
} finally {
videoFile.delete();
+ uninstallAppNoThrow(TEST_APP_A);
}
}
@@ -1274,18 +1278,22 @@
public void testRenameAndReplaceFile() throws Exception {
final File videoFile1 = new File(DCIM_DIR, VIDEO_FILE_NAME);
final File videoFile2 = new File(MOVIES_DIR, VIDEO_FILE_NAME);
+ final ContentResolver cr = getContentResolver();
try {
assertThat(videoFile1.createNewFile()).isTrue();
assertThat(videoFile2.createNewFile()).isTrue();
- final String[] projection = new String[] {MediaColumns._ID};
- // Get id of video file in movies which will be deleted on rename.
- final int id = getFileRowIdFromDatabase(videoFile2);
+ final Uri uriVideoFile1 = MediaStore.scanFile(cr, videoFile1);
+ final Uri uriVideoFile2 = MediaStore.scanFile(cr, videoFile2);
// Renaming a file which replaces file in newPath videoFile2 is allowed.
assertCanRenameFile(videoFile1, videoFile2);
- // MediaProvider database entry for videoFile2 should be deleted on rename.
- assertThat(getFileRowIdFromDatabase(videoFile2)).isNotEqualTo(id);
+ // Uri of videoFile2 should be accessible after rename.
+ assertThat(cr.openFileDescriptor(uriVideoFile2, "rw")).isNotNull();
+ // Uri of videoFile1 should not be accessible after rename.
+ assertThrows(FileNotFoundException.class, () -> {
+ cr.openFileDescriptor(uriVideoFile1, "rw");
+ });
} finally {
videoFile1.delete();
videoFile2.delete();
@@ -1680,8 +1688,12 @@
executeShellCommand("rm " + otherAppPdfFile2);
otherAppImageFile1.delete();
otherAppImageFile2.delete();
+ MediaStore.scanFile(getContentResolver(), otherAppImageFile1);
+ MediaStore.scanFile(getContentResolver(), otherAppImageFile2);
otherAppVideoFile1.delete();
otherAppVideoFile2.delete();
+ MediaStore.scanFile(getContentResolver(), otherAppVideoFile1);
+ MediaStore.scanFile(getContentResolver(), otherAppVideoFile2);
otherAppPdfFile1.delete();
otherAppPdfFile2.delete();
dirInDcim.delete();
@@ -1691,6 +1703,71 @@
}
}
+ /**
+ * Test that row ID corresponding to deleted path is restored on subsequent create.
+ */
+ @Test
+ public void testCreateCanRestoreDeletedRowId() throws Exception {
+ final File imageFile = new File(DCIM_DIR, IMAGE_FILE_NAME);
+ final ContentResolver cr = getContentResolver();
+
+ try {
+ assertThat(imageFile.createNewFile()).isTrue();
+ final long oldRowId = getFileRowIdFromDatabase(imageFile);
+ assertThat(oldRowId).isNotEqualTo(-1);
+ final Uri uriOfOldFile = MediaStore.scanFile(cr, imageFile);
+ assertThat(uriOfOldFile).isNotNull();
+
+ assertThat(imageFile.delete()).isTrue();
+ // We should restore old row Id corresponding to deleted imageFile.
+ assertThat(imageFile.createNewFile()).isTrue();
+ assertThat(getFileRowIdFromDatabase(imageFile)).isEqualTo(oldRowId);
+ assertThat(cr.openFileDescriptor(uriOfOldFile, "rw")).isNotNull();
+
+ assertThat(imageFile.delete()).isTrue();
+ installApp(TEST_APP_A, false);
+ assertThat(createFileAs(TEST_APP_A, imageFile.getAbsolutePath())).isTrue();
+
+ final Uri uriOfNewFile = MediaStore.scanFile(getContentResolver(), imageFile);
+ assertThat(uriOfNewFile).isNotNull();
+ // We shouldn't restore deleted row Id if delete & create are called from different apps
+ assertThat(Integer.getInteger(uriOfNewFile.getLastPathSegment()))
+ .isNotEqualTo(oldRowId);
+ } finally {
+ imageFile.delete();
+ deleteFileAsNoThrow(TEST_APP_A, imageFile.getAbsolutePath());
+ uninstallAppNoThrow(TEST_APP_A);
+ }
+ }
+
+ /**
+ * Test that row ID corresponding to deleted path is restored on subsequent rename.
+ */
+ @Test
+ public void testRenameCanRestoreDeletedRowId() throws Exception {
+ final File imageFile = new File(DCIM_DIR, IMAGE_FILE_NAME);
+ final File temporaryFile = new File(DOWNLOAD_DIR, IMAGE_FILE_NAME + "_.tmp");
+ final ContentResolver cr = getContentResolver();
+
+ try {
+ assertThat(imageFile.createNewFile()).isTrue();
+ final Uri oldUri = MediaStore.scanFile(cr, imageFile);
+ assertThat(oldUri).isNotNull();
+
+ Files.copy(imageFile, temporaryFile);
+ assertThat(imageFile.delete()).isTrue();
+ assertCanRenameFile(temporaryFile, imageFile);
+
+ final Uri newUri = MediaStore.scanFile(cr, imageFile);
+ assertThat(newUri).isNotNull();
+ assertThat(newUri.getLastPathSegment()).isEqualTo(oldUri.getLastPathSegment());
+ // oldUri of imageFile is still accessible after delete and rename.
+ assertThat(cr.openFileDescriptor(oldUri, "rw")).isNotNull();
+ } finally {
+ imageFile.delete();
+ temporaryFile.delete();
+ }
+ }
private static void assertCantQueryFile(File file) {
assertThat(getFileUri(file)).isNull();
}