|
@@ -30,6 +30,7 @@ import org.apache.hadoop.conf.Configuration;
|
|
|
import org.apache.hadoop.fs.BlockLocation;
|
|
|
import org.apache.hadoop.fs.LocalFileSystem;
|
|
|
import org.apache.hadoop.fs.TestFileUtil;
|
|
|
+import org.apache.hadoop.fs.Trash;
|
|
|
import org.apache.hadoop.fs.contract.ContractTestUtils;
|
|
|
import org.apache.hadoop.fs.FileSystem;
|
|
|
import org.apache.hadoop.fs.FileSystemTestHelper;
|
|
@@ -37,6 +38,8 @@ import static org.apache.hadoop.fs.FileSystemTestHelper.*;
|
|
|
import org.apache.hadoop.fs.permission.AclEntry;
|
|
|
import static org.apache.hadoop.fs.viewfs.Constants.PERMISSION_555;
|
|
|
import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_ENABLE_INNER_CACHE;
|
|
|
+import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH;
|
|
|
+import static org.apache.hadoop.fs.FileSystem.TRASH_PREFIX;
|
|
|
import static org.apache.hadoop.test.GenericTestUtils.*;
|
|
|
import static org.junit.Assert.*;
|
|
|
|
|
@@ -951,6 +954,223 @@ abstract public class ViewFileSystemBaseTest {
|
|
|
fsView.deleteSnapshot(new Path("/internalDir"), "snap1");
|
|
|
}
|
|
|
|
|
|
+ @Test
|
|
|
+ public void testTrashRoot() throws IOException {
|
|
|
+
|
|
|
+ Path mountDataRootPath = new Path("/data");
|
|
|
+ Path fsTargetFilePath = new Path("debug.log");
|
|
|
+ Path mountDataFilePath = new Path(mountDataRootPath, fsTargetFilePath);
|
|
|
+ Path mountDataNonExistingFilePath = new Path(mountDataRootPath, "no.log");
|
|
|
+ fileSystemTestHelper.createFile(fsTarget, fsTargetFilePath);
|
|
|
+
|
|
|
+ // Get Trash roots for paths via ViewFileSystem handle
|
|
|
+ Path mountDataRootTrashPath = fsView.getTrashRoot(mountDataRootPath);
|
|
|
+ Path mountDataFileTrashPath = fsView.getTrashRoot(mountDataFilePath);
|
|
|
+
|
|
|
+ // Get Trash roots for the same set of paths via the mounted filesystem
|
|
|
+ Path fsTargetRootTrashRoot = fsTarget.getTrashRoot(mountDataRootPath);
|
|
|
+ Path fsTargetFileTrashPath = fsTarget.getTrashRoot(mountDataFilePath);
|
|
|
+
|
|
|
+ // Verify if Trash roots from ViewFileSystem matches that of the ones
|
|
|
+ // from the target mounted FileSystem.
|
|
|
+ assertEquals(mountDataRootTrashPath.toUri().getPath(),
|
|
|
+ fsTargetRootTrashRoot.toUri().getPath());
|
|
|
+ assertEquals(mountDataFileTrashPath.toUri().getPath(),
|
|
|
+ fsTargetFileTrashPath.toUri().getPath());
|
|
|
+ assertEquals(mountDataRootTrashPath.toUri().getPath(),
|
|
|
+ mountDataFileTrashPath.toUri().getPath());
|
|
|
+
|
|
|
+
|
|
|
+ // Verify trash root for an non-existing file but on a valid mountpoint.
|
|
|
+ Path trashRoot = fsView.getTrashRoot(mountDataNonExistingFilePath);
|
|
|
+ assertEquals(mountDataRootTrashPath.toUri().getPath(),
|
|
|
+ trashRoot.toUri().getPath());
|
|
|
+
|
|
|
+ // Verify trash root for invalid mounts.
|
|
|
+ Path invalidMountRootPath = new Path("/invalid_mount");
|
|
|
+ Path invalidMountFilePath = new Path(invalidMountRootPath, "debug.log");
|
|
|
+ try {
|
|
|
+ fsView.getTrashRoot(invalidMountRootPath);
|
|
|
+ fail("ViewFileSystem getTashRoot should fail for non-mountpoint paths.");
|
|
|
+ } catch (NotInMountpointException e) {
|
|
|
+ //expected exception
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ fsView.getTrashRoot(invalidMountFilePath);
|
|
|
+ fail("ViewFileSystem getTashRoot should fail for non-mountpoint paths.");
|
|
|
+ } catch (NotInMountpointException e) {
|
|
|
+ //expected exception
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ fsView.getTrashRoot(null);
|
|
|
+ fail("ViewFileSystem getTashRoot should fail for empty paths.");
|
|
|
+ } catch (NotInMountpointException e) {
|
|
|
+ //expected exception
|
|
|
+ }
|
|
|
+
|
|
|
+ // Move the file to trash
|
|
|
+ FileStatus fileStatus = fsTarget.getFileStatus(fsTargetFilePath);
|
|
|
+ Configuration newConf = new Configuration(conf);
|
|
|
+ newConf.setLong("fs.trash.interval", 1000);
|
|
|
+ Trash lTrash = new Trash(fsTarget, newConf);
|
|
|
+ boolean trashed = lTrash.moveToTrash(fsTargetFilePath);
|
|
|
+ Assert.assertTrue("File " + fileStatus + " move to " +
|
|
|
+ "trash failed.", trashed);
|
|
|
+
|
|
|
+ // Verify ViewFileSystem trash roots shows the ones from
|
|
|
+ // target mounted FileSystem.
|
|
|
+ Assert.assertTrue("", fsView.getTrashRoots(true).size() > 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Test the localized trash root for getTrashRoot.
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ public void testTrashRootLocalizedTrash() throws IOException {
|
|
|
+ UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
|
|
|
+ Configuration conf2 = new Configuration(conf);
|
|
|
+ conf2.setBoolean(CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH, true);
|
|
|
+ FileSystem fsView2 = FileSystem.get(FsConstants.VIEWFS_URI, conf2);
|
|
|
+
|
|
|
+ // Case 1: path p not in the default FS.
|
|
|
+ // Return a trash root within the mount point.
|
|
|
+ Path dataTestPath = new Path("/data/dir/file");
|
|
|
+ Path dataTrashRoot = new Path(targetTestRoot,
|
|
|
+ "data/" + TRASH_PREFIX + "/" + ugi.getShortUserName());
|
|
|
+ Assert.assertEquals(dataTrashRoot, fsView2.getTrashRoot(dataTestPath));
|
|
|
+
|
|
|
+ // Case 2: turn off the CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH flag.
|
|
|
+ // Return a trash root in user home dir.
|
|
|
+ Path nonExistentPath = new Path("/nonExistentDir/nonExistentFile");
|
|
|
+ Path userTrashRoot = new Path(fsTarget.getHomeDirectory(), TRASH_PREFIX);
|
|
|
+ conf2.setBoolean(CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH, false);
|
|
|
+ fsView2 = FileSystem.get(FsConstants.VIEWFS_URI, conf2);
|
|
|
+ Assert.assertEquals(userTrashRoot, fsView2.getTrashRoot(dataTestPath));
|
|
|
+
|
|
|
+ // Case 3: viewFS without fallback. Expect exception for a nonExistent path
|
|
|
+ conf2 = new Configuration(conf);
|
|
|
+ fsView2 = FileSystem.get(FsConstants.VIEWFS_URI, conf2);
|
|
|
+ try {
|
|
|
+ fsView2.getTrashRoot(nonExistentPath);
|
|
|
+ } catch (NotInMountpointException ignored) {
|
|
|
+ }
|
|
|
+
|
|
|
+ // Case 4: path p is in the same mount point as targetFS.getTrashRoot().
|
|
|
+ // Return targetFS.getTrashRoot()
|
|
|
+ // Use a new Configuration object, so that we can start with an empty
|
|
|
+ // mount table. This would avoid a conflict between the /user link in
|
|
|
+ // setupMountPoints() and homeDir we will need to setup for this test.
|
|
|
+ // default homeDir for hdfs is /user/.
|
|
|
+ Configuration conf3 = ViewFileSystemTestSetup.createConfig();
|
|
|
+ Path homeDir = fsTarget.getHomeDirectory();
|
|
|
+ String homeParentDir = homeDir.getParent().toUri().getPath();
|
|
|
+ conf3.setBoolean(CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH, true);
|
|
|
+ ConfigUtil.addLink(conf3, homeParentDir,
|
|
|
+ new Path(targetTestRoot, homeParentDir).toUri());
|
|
|
+ Path homeTestPath = new Path(homeDir.toUri().getPath(), "testuser/file");
|
|
|
+ FileSystem fsView3 = FileSystem.get(FsConstants.VIEWFS_URI, conf3);
|
|
|
+ Assert.assertEquals(userTrashRoot, fsView3.getTrashRoot(homeTestPath));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * A mocked FileSystem which returns a deep trash dir.
|
|
|
+ */
|
|
|
+ static class MockTrashRootFS extends MockFileSystem {
|
|
|
+ public static final Path TRASH =
|
|
|
+ new Path("/mnt/very/deep/deep/trash/dir/.Trash");
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Path getTrashRoot(Path path) {
|
|
|
+ return TRASH;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Test a trash root that is inside a mount point for getTrashRoot.
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ public void testTrashRootDeepTrashDir() throws IOException {
|
|
|
+
|
|
|
+ Configuration conf2 = ViewFileSystemTestSetup.createConfig();
|
|
|
+ conf2.setBoolean(CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH, true);
|
|
|
+ conf2.setClass("fs.mocktrashfs.impl", MockTrashRootFS.class,
|
|
|
+ FileSystem.class);
|
|
|
+ ConfigUtil.addLink(conf2, "/mnt", URI.create("mocktrashfs://mnt/path"));
|
|
|
+ Path testPath = new Path(MockTrashRootFS.TRASH, "projs/proj");
|
|
|
+ FileSystem fsView2 = FileSystem.get(FsConstants.VIEWFS_URI, conf2);
|
|
|
+ Assert.assertEquals(MockTrashRootFS.TRASH, fsView2.getTrashRoot(testPath));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Test localized trash roots in getTrashRoots() for all users.
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ public void testTrashRootsAllUsers() throws IOException {
|
|
|
+ Configuration conf2 = new Configuration(conf);
|
|
|
+ conf2.setBoolean(CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH, true);
|
|
|
+ FileSystem fsView2 = FileSystem.get(FsConstants.VIEWFS_URI, conf2);
|
|
|
+
|
|
|
+ // Case 1: verify correct trash roots from fsView and fsView2
|
|
|
+ int beforeTrashRootNum = fsView.getTrashRoots(true).size();
|
|
|
+ int beforeTrashRootNum2 = fsView2.getTrashRoots(true).size();
|
|
|
+ Assert.assertEquals(beforeTrashRootNum, beforeTrashRootNum2);
|
|
|
+
|
|
|
+ fsView.mkdirs(new Path("/data/" + TRASH_PREFIX + "/user1"));
|
|
|
+ fsView.mkdirs(new Path("/data/" + TRASH_PREFIX + "/user2"));
|
|
|
+ fsView.mkdirs(new Path("/user/" + TRASH_PREFIX + "/user3"));
|
|
|
+ fsView.mkdirs(new Path("/user/" + TRASH_PREFIX + "/user4"));
|
|
|
+ fsView.mkdirs(new Path("/user2/" + TRASH_PREFIX + "/user5"));
|
|
|
+ int afterTrashRootsNum = fsView.getTrashRoots(true).size();
|
|
|
+ int afterTrashRootsNum2 = fsView2.getTrashRoots(true).size();
|
|
|
+ Assert.assertEquals(beforeTrashRootNum, afterTrashRootsNum);
|
|
|
+ Assert.assertEquals(beforeTrashRootNum2 + 5, afterTrashRootsNum2);
|
|
|
+
|
|
|
+ // Case 2: per-user mount point
|
|
|
+ fsTarget.mkdirs(new Path(targetTestRoot, "Users/userA/.Trash/userA"));
|
|
|
+ Configuration conf3 = new Configuration(conf2);
|
|
|
+ ConfigUtil.addLink(conf3, "/Users/userA",
|
|
|
+ new Path(targetTestRoot, "Users/userA").toUri());
|
|
|
+ FileSystem fsView3 = FileSystem.get(FsConstants.VIEWFS_URI, conf3);
|
|
|
+ int trashRootsNum3 = fsView3.getTrashRoots(true).size();
|
|
|
+ Assert.assertEquals(afterTrashRootsNum2 + 1, trashRootsNum3);
|
|
|
+
|
|
|
+ // Case 3: single /Users mount point for all users
|
|
|
+ fsTarget.mkdirs(new Path(targetTestRoot, "Users/.Trash/user1"));
|
|
|
+ fsTarget.mkdirs(new Path(targetTestRoot, "Users/.Trash/user2"));
|
|
|
+ Configuration conf4 = new Configuration(conf2);
|
|
|
+ ConfigUtil.addLink(conf4, "/Users",
|
|
|
+ new Path(targetTestRoot, "Users").toUri());
|
|
|
+ FileSystem fsView4 = FileSystem.get(FsConstants.VIEWFS_URI, conf4);
|
|
|
+ int trashRootsNum4 = fsView4.getTrashRoots(true).size();
|
|
|
+ Assert.assertEquals(afterTrashRootsNum2 + 2, trashRootsNum4);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Test localized trash roots in getTrashRoots() for current user.
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ public void testTrashRootsCurrentUser() throws IOException {
|
|
|
+ String currentUser =
|
|
|
+ UserGroupInformation.getCurrentUser().getShortUserName();
|
|
|
+ Configuration conf2 = new Configuration(conf);
|
|
|
+ conf2.setBoolean(CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH, true);
|
|
|
+ FileSystem fsView2 = FileSystem.get(FsConstants.VIEWFS_URI, conf2);
|
|
|
+
|
|
|
+ int beforeTrashRootNum = fsView.getTrashRoots(false).size();
|
|
|
+ int beforeTrashRootNum2 = fsView2.getTrashRoots(false).size();
|
|
|
+ Assert.assertEquals(beforeTrashRootNum, beforeTrashRootNum2);
|
|
|
+
|
|
|
+ fsView.mkdirs(new Path("/data/" + TRASH_PREFIX + "/" + currentUser));
|
|
|
+ fsView.mkdirs(new Path("/data/" + TRASH_PREFIX + "/user2"));
|
|
|
+ fsView.mkdirs(new Path("/user/" + TRASH_PREFIX + "/" + currentUser));
|
|
|
+ fsView.mkdirs(new Path("/user/" + TRASH_PREFIX + "/user4"));
|
|
|
+ fsView.mkdirs(new Path("/user2/" + TRASH_PREFIX + "/user5"));
|
|
|
+ int afterTrashRootsNum = fsView.getTrashRoots(false).size();
|
|
|
+ int afterTrashRootsNum2 = fsView2.getTrashRoots(false).size();
|
|
|
+ Assert.assertEquals(beforeTrashRootNum, afterTrashRootsNum);
|
|
|
+ Assert.assertEquals(beforeTrashRootNum2 + 2, afterTrashRootsNum2);
|
|
|
+ }
|
|
|
+
|
|
|
@Test
|
|
|
public void testCheckOwnerWithFileStatus()
|
|
|
throws IOException, InterruptedException {
|