| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.apache.hadoop.fs.viewfs; |
| |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.net.URI; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.fs.FileStatus; |
| import org.apache.hadoop.fs.ContentSummary; |
| import org.apache.hadoop.fs.FileSystem; |
| import org.apache.hadoop.fs.FileSystemTestHelper; |
| import org.apache.hadoop.fs.FilterFileSystem; |
| import org.apache.hadoop.fs.FsConstants; |
| import org.apache.hadoop.fs.Path; |
| import org.apache.hadoop.fs.permission.AclEntry; |
| import org.apache.hadoop.fs.viewfs.ChRootedFileSystem; |
| import org.junit.After; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| import static org.mockito.Mockito.*; |
| |
| public class TestChRootedFileSystem { |
| FileSystem fSys; // The ChRoootedFs |
| FileSystem fSysTarget; // |
| Path chrootedTo; |
| FileSystemTestHelper fileSystemTestHelper; |
| |
| @Before |
| public void setUp() throws Exception { |
| // create the test root on local_fs |
| Configuration conf = new Configuration(); |
| fSysTarget = FileSystem.getLocal(conf); |
| fileSystemTestHelper = new FileSystemTestHelper(); |
| chrootedTo = fileSystemTestHelper.getAbsoluteTestRootPath(fSysTarget); |
| // In case previous test was killed before cleanup |
| fSysTarget.delete(chrootedTo, true); |
| |
| fSysTarget.mkdirs(chrootedTo); |
| |
| |
| // ChRoot to the root of the testDirectory |
| fSys = new ChRootedFileSystem(chrootedTo.toUri(), conf); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| fSysTarget.delete(chrootedTo, true); |
| } |
| |
| @Test |
| public void testURI() { |
| URI uri = fSys.getUri(); |
| Assert.assertEquals(chrootedTo.toUri(), uri); |
| } |
| |
| @Test |
| public void testBasicPaths() { |
| URI uri = fSys.getUri(); |
| Assert.assertEquals(chrootedTo.toUri(), uri); |
| Assert.assertEquals(fSys.makeQualified( |
| new Path(System.getProperty("user.home"))), |
| fSys.getWorkingDirectory()); |
| Assert.assertEquals(fSys.makeQualified( |
| new Path(System.getProperty("user.home"))), |
| fSys.getHomeDirectory()); |
| /* |
| * ChRootedFs as its uri like file:///chrootRoot. |
| * This is questionable since path.makequalified(uri, path) ignores |
| * the pathPart of a uri. So our notion of chrooted URI is questionable. |
| * But if we were to fix Path#makeQualified() then the next test should |
| * have been: |
| |
| Assert.assertEquals( |
| new Path(chrootedTo + "/foo/bar").makeQualified( |
| FsConstants.LOCAL_FS_URI, null), |
| fSys.makeQualified(new Path( "/foo/bar"))); |
| */ |
| |
| Assert.assertEquals( |
| new Path("/foo/bar").makeQualified(FsConstants.LOCAL_FS_URI, null), |
| fSys.makeQualified(new Path("/foo/bar"))); |
| } |
| |
| /** |
| * Test modify operations (create, mkdir, delete, etc) |
| * |
| * Verify the operation via chrootedfs (ie fSys) and *also* via the |
| * target file system (ie fSysTarget) that has been chrooted. |
| */ |
| @Test |
| public void testCreateDelete() throws IOException { |
| |
| |
| // Create file |
| fileSystemTestHelper.createFile(fSys, "/foo"); |
| Assert.assertTrue(fSys.isFile(new Path("/foo"))); |
| Assert.assertTrue(fSysTarget.isFile(new Path(chrootedTo, "foo"))); |
| |
| // Create file with recursive dir |
| fileSystemTestHelper.createFile(fSys, "/newDir/foo"); |
| Assert.assertTrue(fSys.isFile(new Path("/newDir/foo"))); |
| Assert.assertTrue(fSysTarget.isFile(new Path(chrootedTo,"newDir/foo"))); |
| |
| // Delete the created file |
| Assert.assertTrue(fSys.delete(new Path("/newDir/foo"), false)); |
| Assert.assertFalse(fSys.exists(new Path("/newDir/foo"))); |
| Assert.assertFalse(fSysTarget.exists(new Path(chrootedTo, "newDir/foo"))); |
| |
| // Create file with a 2 component dirs recursively |
| fileSystemTestHelper.createFile(fSys, "/newDir/newDir2/foo"); |
| Assert.assertTrue(fSys.isFile(new Path("/newDir/newDir2/foo"))); |
| Assert.assertTrue(fSysTarget.isFile(new Path(chrootedTo,"newDir/newDir2/foo"))); |
| |
| // Delete the created file |
| Assert.assertTrue(fSys.delete(new Path("/newDir/newDir2/foo"), false)); |
| Assert.assertFalse(fSys.exists(new Path("/newDir/newDir2/foo"))); |
| Assert.assertFalse(fSysTarget.exists(new Path(chrootedTo,"newDir/newDir2/foo"))); |
| } |
| |
| |
| @Test |
| public void testMkdirDelete() throws IOException { |
| fSys.mkdirs(fileSystemTestHelper.getTestRootPath(fSys, "/dirX")); |
| Assert.assertTrue(fSys.isDirectory(new Path("/dirX"))); |
| Assert.assertTrue(fSysTarget.isDirectory(new Path(chrootedTo,"dirX"))); |
| |
| fSys.mkdirs(fileSystemTestHelper.getTestRootPath(fSys, "/dirX/dirY")); |
| Assert.assertTrue(fSys.isDirectory(new Path("/dirX/dirY"))); |
| Assert.assertTrue(fSysTarget.isDirectory(new Path(chrootedTo,"dirX/dirY"))); |
| |
| |
| // Delete the created dir |
| Assert.assertTrue(fSys.delete(new Path("/dirX/dirY"), false)); |
| Assert.assertFalse(fSys.exists(new Path("/dirX/dirY"))); |
| Assert.assertFalse(fSysTarget.exists(new Path(chrootedTo,"dirX/dirY"))); |
| |
| Assert.assertTrue(fSys.delete(new Path("/dirX"), false)); |
| Assert.assertFalse(fSys.exists(new Path("/dirX"))); |
| Assert.assertFalse(fSysTarget.exists(new Path(chrootedTo,"dirX"))); |
| |
| } |
| @Test |
| public void testRename() throws IOException { |
| // Rename a file |
| fileSystemTestHelper.createFile(fSys, "/newDir/foo"); |
| fSys.rename(new Path("/newDir/foo"), new Path("/newDir/fooBar")); |
| Assert.assertFalse(fSys.exists(new Path("/newDir/foo"))); |
| Assert.assertFalse(fSysTarget.exists(new Path(chrootedTo,"newDir/foo"))); |
| Assert.assertTrue(fSys.isFile(fileSystemTestHelper.getTestRootPath(fSys,"/newDir/fooBar"))); |
| Assert.assertTrue(fSysTarget.isFile(new Path(chrootedTo,"newDir/fooBar"))); |
| |
| |
| // Rename a dir |
| fSys.mkdirs(new Path("/newDir/dirFoo")); |
| fSys.rename(new Path("/newDir/dirFoo"), new Path("/newDir/dirFooBar")); |
| Assert.assertFalse(fSys.exists(new Path("/newDir/dirFoo"))); |
| Assert.assertFalse(fSysTarget.exists(new Path(chrootedTo,"newDir/dirFoo"))); |
| Assert.assertTrue(fSys.isDirectory(fileSystemTestHelper.getTestRootPath(fSys,"/newDir/dirFooBar"))); |
| Assert.assertTrue(fSysTarget.isDirectory(new Path(chrootedTo,"newDir/dirFooBar"))); |
| } |
| |
| @Test |
| public void testGetContentSummary() throws IOException { |
| // GetContentSummary of a dir |
| fSys.mkdirs(new Path("/newDir/dirFoo")); |
| ContentSummary cs = fSys.getContentSummary(new Path("/newDir/dirFoo")); |
| Assert.assertEquals(-1L, cs.getQuota()); |
| Assert.assertEquals(-1L, cs.getSpaceQuota()); |
| } |
| |
| /** |
| * We would have liked renames across file system to fail but |
| * Unfortunately there is not way to distinguish the two file systems |
| * @throws IOException |
| */ |
| @Test |
| public void testRenameAcrossFs() throws IOException { |
| fSys.mkdirs(new Path("/newDir/dirFoo")); |
| fSys.rename(new Path("/newDir/dirFoo"), new Path("file:///tmp/dirFooBar")); |
| FileSystemTestHelper.isDir(fSys, new Path("/tmp/dirFooBar")); |
| } |
| |
| |
| |
| |
| @Test |
| public void testList() throws IOException { |
| |
| FileStatus fs = fSys.getFileStatus(new Path("/")); |
| Assert.assertTrue(fs.isDirectory()); |
| // should return the full path not the chrooted path |
| Assert.assertEquals(fs.getPath(), chrootedTo); |
| |
| // list on Slash |
| |
| FileStatus[] dirPaths = fSys.listStatus(new Path("/")); |
| |
| Assert.assertEquals(0, dirPaths.length); |
| |
| |
| |
| fileSystemTestHelper.createFile(fSys, "/foo"); |
| fileSystemTestHelper.createFile(fSys, "/bar"); |
| fSys.mkdirs(new Path("/dirX")); |
| fSys.mkdirs(fileSystemTestHelper.getTestRootPath(fSys, "/dirY")); |
| fSys.mkdirs(new Path("/dirX/dirXX")); |
| |
| dirPaths = fSys.listStatus(new Path("/")); |
| Assert.assertEquals(4, dirPaths.length); // note 2 crc files |
| |
| // Note the the file status paths are the full paths on target |
| fs = FileSystemTestHelper.containsPath(new Path(chrootedTo, "foo"), dirPaths); |
| Assert.assertNotNull(fs); |
| Assert.assertTrue(fs.isFile()); |
| fs = FileSystemTestHelper.containsPath(new Path(chrootedTo, "bar"), dirPaths); |
| Assert.assertNotNull(fs); |
| Assert.assertTrue(fs.isFile()); |
| fs = FileSystemTestHelper.containsPath(new Path(chrootedTo, "dirX"), dirPaths); |
| Assert.assertNotNull(fs); |
| Assert.assertTrue(fs.isDirectory()); |
| fs = FileSystemTestHelper.containsPath(new Path(chrootedTo, "dirY"), dirPaths); |
| Assert.assertNotNull(fs); |
| Assert.assertTrue(fs.isDirectory()); |
| } |
| |
| @Test |
| public void testWorkingDirectory() throws Exception { |
| |
| // First we cd to our test root |
| fSys.mkdirs(new Path("/testWd")); |
| Path workDir = new Path("/testWd"); |
| fSys.setWorkingDirectory(workDir); |
| Assert.assertEquals(workDir, fSys.getWorkingDirectory()); |
| |
| fSys.setWorkingDirectory(new Path(".")); |
| Assert.assertEquals(workDir, fSys.getWorkingDirectory()); |
| |
| fSys.setWorkingDirectory(new Path("..")); |
| Assert.assertEquals(workDir.getParent(), fSys.getWorkingDirectory()); |
| |
| // cd using a relative path |
| |
| // Go back to our test root |
| workDir = new Path("/testWd"); |
| fSys.setWorkingDirectory(workDir); |
| Assert.assertEquals(workDir, fSys.getWorkingDirectory()); |
| |
| Path relativeDir = new Path("existingDir1"); |
| Path absoluteDir = new Path(workDir,"existingDir1"); |
| fSys.mkdirs(absoluteDir); |
| fSys.setWorkingDirectory(relativeDir); |
| Assert.assertEquals(absoluteDir, fSys.getWorkingDirectory()); |
| // cd using a absolute path |
| absoluteDir = new Path("/test/existingDir2"); |
| fSys.mkdirs(absoluteDir); |
| fSys.setWorkingDirectory(absoluteDir); |
| Assert.assertEquals(absoluteDir, fSys.getWorkingDirectory()); |
| |
| // Now open a file relative to the wd we just set above. |
| Path absoluteFooPath = new Path(absoluteDir, "foo"); |
| fSys.create(absoluteFooPath).close(); |
| fSys.open(new Path("foo")).close(); |
| |
| // Now mkdir relative to the dir we cd'ed to |
| fSys.mkdirs(new Path("newDir")); |
| Assert.assertTrue(fSys.isDirectory(new Path(absoluteDir, "newDir"))); |
| |
| /* Filesystem impls (RawLocal and DistributedFileSystem do not check |
| * for existing of working dir |
| absoluteDir = getTestRootPath(fSys, "nonexistingPath"); |
| try { |
| fSys.setWorkingDirectory(absoluteDir); |
| Assert.fail("cd to non existing dir should have failed"); |
| } catch (Exception e) { |
| // Exception as expected |
| } |
| */ |
| |
| // Try a URI |
| final String LOCAL_FS_ROOT_URI = "file:///tmp/test"; |
| absoluteDir = new Path(LOCAL_FS_ROOT_URI + "/existingDir"); |
| fSys.mkdirs(absoluteDir); |
| fSys.setWorkingDirectory(absoluteDir); |
| Assert.assertEquals(absoluteDir, fSys.getWorkingDirectory()); |
| |
| } |
| |
| /* |
| * Test resolvePath(p) |
| */ |
| |
| @Test |
| public void testResolvePath() throws IOException { |
| Assert.assertEquals(chrootedTo, fSys.resolvePath(new Path("/"))); |
| fileSystemTestHelper.createFile(fSys, "/foo"); |
| Assert.assertEquals(new Path(chrootedTo, "foo"), |
| fSys.resolvePath(new Path("/foo"))); |
| } |
| |
| @Test(expected=FileNotFoundException.class) |
| public void testResolvePathNonExisting() throws IOException { |
| fSys.resolvePath(new Path("/nonExisting")); |
| } |
| |
| @Test |
| public void testDeleteOnExitPathHandling() throws IOException { |
| Configuration conf = new Configuration(); |
| conf.setClass("fs.mockfs.impl", MockFileSystem.class, FileSystem.class); |
| |
| URI chrootUri = URI.create("mockfs://foo/a/b"); |
| ChRootedFileSystem chrootFs = new ChRootedFileSystem(chrootUri, conf); |
| FileSystem mockFs = ((FilterFileSystem)chrootFs.getRawFileSystem()) |
| .getRawFileSystem(); |
| |
| // ensure delete propagates the correct path |
| Path chrootPath = new Path("/c"); |
| Path rawPath = new Path("/a/b/c"); |
| chrootFs.delete(chrootPath, false); |
| verify(mockFs).delete(eq(rawPath), eq(false)); |
| reset(mockFs); |
| |
| // fake that the path exists for deleteOnExit |
| FileStatus stat = mock(FileStatus.class); |
| when(mockFs.getFileStatus(eq(rawPath))).thenReturn(stat); |
| // ensure deleteOnExit propagates the correct path |
| chrootFs.deleteOnExit(chrootPath); |
| chrootFs.close(); |
| verify(mockFs).delete(eq(rawPath), eq(true)); |
| } |
| |
| @Test |
| public void testURIEmptyPath() throws IOException { |
| Configuration conf = new Configuration(); |
| conf.setClass("fs.mockfs.impl", MockFileSystem.class, FileSystem.class); |
| |
| URI chrootUri = URI.create("mockfs://foo"); |
| new ChRootedFileSystem(chrootUri, conf); |
| } |
| |
| /** |
| * Tests that ChRootedFileSystem delegates calls for every ACL method to the |
| * underlying FileSystem with all Path arguments translated as required to |
| * enforce chroot. |
| */ |
| @Test |
| public void testAclMethodsPathTranslation() throws IOException { |
| Configuration conf = new Configuration(); |
| conf.setClass("fs.mockfs.impl", MockFileSystem.class, FileSystem.class); |
| |
| URI chrootUri = URI.create("mockfs://foo/a/b"); |
| ChRootedFileSystem chrootFs = new ChRootedFileSystem(chrootUri, conf); |
| FileSystem mockFs = ((FilterFileSystem)chrootFs.getRawFileSystem()) |
| .getRawFileSystem(); |
| |
| Path chrootPath = new Path("/c"); |
| Path rawPath = new Path("/a/b/c"); |
| List<AclEntry> entries = Collections.emptyList(); |
| |
| chrootFs.modifyAclEntries(chrootPath, entries); |
| verify(mockFs).modifyAclEntries(rawPath, entries); |
| |
| chrootFs.removeAclEntries(chrootPath, entries); |
| verify(mockFs).removeAclEntries(rawPath, entries); |
| |
| chrootFs.removeDefaultAcl(chrootPath); |
| verify(mockFs).removeDefaultAcl(rawPath); |
| |
| chrootFs.removeAcl(chrootPath); |
| verify(mockFs).removeAcl(rawPath); |
| |
| chrootFs.setAcl(chrootPath, entries); |
| verify(mockFs).setAcl(rawPath, entries); |
| |
| chrootFs.getAclStatus(chrootPath); |
| verify(mockFs).getAclStatus(rawPath); |
| } |
| |
| @Test |
| public void testListLocatedFileStatus() throws IOException { |
| final Path mockMount = new Path("mockfs://foo/user"); |
| final Path mockPath = new Path("/usermock"); |
| final Configuration conf = new Configuration(); |
| conf.setClass("fs.mockfs.impl", MockFileSystem.class, FileSystem.class); |
| ConfigUtil.addLink(conf, mockPath.toString(), mockMount.toUri()); |
| FileSystem vfs = FileSystem.get(URI.create("viewfs:///"), conf); |
| vfs.listLocatedStatus(mockPath); |
| final FileSystem mockFs = ((MockFileSystem)mockMount.getFileSystem(conf)) |
| .getRawFileSystem(); |
| verify(mockFs).listLocatedStatus(new Path(mockMount.toUri().getPath())); |
| } |
| |
| static class MockFileSystem extends FilterFileSystem { |
| MockFileSystem() { |
| super(mock(FileSystem.class)); |
| } |
| @Override |
| public void initialize(URI name, Configuration conf) throws IOException {} |
| } |
| |
| @Test(timeout = 30000) |
| public void testCreateSnapshot() throws Exception { |
| Path snapRootPath = new Path("/snapPath"); |
| Path chRootedSnapRootPath = new Path("/a/b/snapPath"); |
| |
| Configuration conf = new Configuration(); |
| conf.setClass("fs.mockfs.impl", MockFileSystem.class, FileSystem.class); |
| |
| URI chrootUri = URI.create("mockfs://foo/a/b"); |
| ChRootedFileSystem chrootFs = new ChRootedFileSystem(chrootUri, conf); |
| FileSystem mockFs = ((FilterFileSystem) chrootFs.getRawFileSystem()) |
| .getRawFileSystem(); |
| |
| chrootFs.createSnapshot(snapRootPath, "snap1"); |
| verify(mockFs).createSnapshot(chRootedSnapRootPath, "snap1"); |
| } |
| |
| @Test(timeout = 30000) |
| public void testDeleteSnapshot() throws Exception { |
| Path snapRootPath = new Path("/snapPath"); |
| Path chRootedSnapRootPath = new Path("/a/b/snapPath"); |
| |
| Configuration conf = new Configuration(); |
| conf.setClass("fs.mockfs.impl", MockFileSystem.class, FileSystem.class); |
| |
| URI chrootUri = URI.create("mockfs://foo/a/b"); |
| ChRootedFileSystem chrootFs = new ChRootedFileSystem(chrootUri, conf); |
| FileSystem mockFs = ((FilterFileSystem) chrootFs.getRawFileSystem()) |
| .getRawFileSystem(); |
| |
| chrootFs.deleteSnapshot(snapRootPath, "snap1"); |
| verify(mockFs).deleteSnapshot(chRootedSnapRootPath, "snap1"); |
| } |
| |
| @Test(timeout = 30000) |
| public void testRenameSnapshot() throws Exception { |
| Path snapRootPath = new Path("/snapPath"); |
| Path chRootedSnapRootPath = new Path("/a/b/snapPath"); |
| |
| Configuration conf = new Configuration(); |
| conf.setClass("fs.mockfs.impl", MockFileSystem.class, FileSystem.class); |
| |
| URI chrootUri = URI.create("mockfs://foo/a/b"); |
| ChRootedFileSystem chrootFs = new ChRootedFileSystem(chrootUri, conf); |
| FileSystem mockFs = ((FilterFileSystem) chrootFs.getRawFileSystem()) |
| .getRawFileSystem(); |
| |
| chrootFs.renameSnapshot(snapRootPath, "snapOldName", "snapNewName"); |
| verify(mockFs).renameSnapshot(chRootedSnapRootPath, "snapOldName", |
| "snapNewName"); |
| } |
| } |