aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/lib/vfs/FileSystemUtilsTest.java
diff options
context:
space:
mode:
authorGravatar Han-Wen Nienhuys <hanwen@google.com>2015-02-25 16:45:20 +0100
committerGravatar Han-Wen Nienhuys <hanwen@google.com>2015-02-25 16:45:20 +0100
commitd08b27fa9701fecfdb69e1b0d1ac2459efc2129b (patch)
tree5d50963026239ca5aebfb47ea5b8db7e814e57c8 /src/test/java/com/google/devtools/build/lib/vfs/FileSystemUtilsTest.java
Update from Google.
-- MOE_MIGRATED_REVID=85702957
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/vfs/FileSystemUtilsTest.java')
-rw-r--r--src/test/java/com/google/devtools/build/lib/vfs/FileSystemUtilsTest.java878
1 files changed, 878 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/vfs/FileSystemUtilsTest.java b/src/test/java/com/google/devtools/build/lib/vfs/FileSystemUtilsTest.java
new file mode 100644
index 0000000000..21ca39b8f0
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/vfs/FileSystemUtilsTest.java
@@ -0,0 +1,878 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// 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.devtools.build.lib.vfs;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.lib.vfs.FileSystemUtils.appendWithoutExtension;
+import static com.google.devtools.build.lib.vfs.FileSystemUtils.commonAncestor;
+import static com.google.devtools.build.lib.vfs.FileSystemUtils.copyFile;
+import static com.google.devtools.build.lib.vfs.FileSystemUtils.copyTool;
+import static com.google.devtools.build.lib.vfs.FileSystemUtils.createDirectoryAndParents;
+import static com.google.devtools.build.lib.vfs.FileSystemUtils.deleteTree;
+import static com.google.devtools.build.lib.vfs.FileSystemUtils.deleteTreesBelowNotPrefixed;
+import static com.google.devtools.build.lib.vfs.FileSystemUtils.longestPathPrefix;
+import static com.google.devtools.build.lib.vfs.FileSystemUtils.plantLinkForest;
+import static com.google.devtools.build.lib.vfs.FileSystemUtils.relativePath;
+import static com.google.devtools.build.lib.vfs.FileSystemUtils.removeExtension;
+import static com.google.devtools.build.lib.vfs.FileSystemUtils.touchFile;
+import static com.google.devtools.build.lib.vfs.FileSystemUtils.traverseTree;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.devtools.build.lib.testutil.BlazeTestUtils;
+import com.google.devtools.build.lib.testutil.ManualClock;
+import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class tests the file system utilities.
+ */
+@RunWith(JUnit4.class)
+public class FileSystemUtilsTest {
+ private ManualClock clock;
+ private FileSystem fileSystem;
+ private Path workingDir;
+
+ @Before
+ public void setUp() throws Exception {
+ clock = new ManualClock();
+ fileSystem = new InMemoryFileSystem(clock);
+ workingDir = fileSystem.getPath("/workingDir");
+ }
+
+ Path topDir;
+ Path file1;
+ Path file2;
+ Path aDir;
+ Path file3;
+ Path innerDir;
+ Path link1;
+ Path dirLink;
+ Path file4;
+
+ /*
+ * Build a directory tree that looks like:
+ * top-dir/
+ * file-1
+ * file-2
+ * a-dir/
+ * file-3
+ * inner-dir/
+ * link-1 => file-4
+ * dir-link => a-dir
+ * file-4
+ */
+ private void createTestDirectoryTree() throws IOException {
+ topDir = fileSystem.getPath("/top-dir");
+ file1 = fileSystem.getPath("/top-dir/file-1");
+ file2 = fileSystem.getPath("/top-dir/file-2");
+ aDir = fileSystem.getPath("/top-dir/a-dir");
+ file3 = fileSystem.getPath("/top-dir/a-dir/file-3");
+ innerDir = fileSystem.getPath("/top-dir/a-dir/inner-dir");
+ link1 = fileSystem.getPath("/top-dir/a-dir/inner-dir/link-1");
+ dirLink = fileSystem.getPath("/top-dir/a-dir/inner-dir/dir-link");
+ file4 = fileSystem.getPath("/file-4");
+
+ topDir.createDirectory();
+ FileSystemUtils.createEmptyFile(file1);
+ FileSystemUtils.createEmptyFile(file2);
+ aDir.createDirectory();
+ FileSystemUtils.createEmptyFile(file3);
+ innerDir.createDirectory();
+ link1.createSymbolicLink(file4); // simple symlink
+ dirLink.createSymbolicLink(aDir); // creates link loop
+ FileSystemUtils.createEmptyFile(file4);
+ }
+
+ private void checkTestDirectoryTreesBelow(Path toPath) throws IOException {
+ Path copiedFile1 = toPath.getChild("file-1");
+ assertTrue(copiedFile1.exists());
+ assertTrue(copiedFile1.isFile());
+
+ Path copiedFile2 = toPath.getChild("file-2");
+ assertTrue(copiedFile2.exists());
+ assertTrue(copiedFile2.isFile());
+
+ Path copiedADir = toPath.getChild("a-dir");
+ assertTrue(copiedADir.exists());
+ assertTrue(copiedADir.isDirectory());
+ Collection<Path> aDirEntries = copiedADir.getDirectoryEntries();
+ assertEquals(2, aDirEntries.size());
+
+ Path copiedFile3 = copiedADir.getChild("file-3");
+ assertTrue(copiedFile3.exists());
+ assertTrue(copiedFile3.isFile());
+
+ Path copiedInnerDir = copiedADir.getChild("inner-dir");
+ assertTrue(copiedInnerDir.exists());
+ assertTrue(copiedInnerDir.isDirectory());
+
+ Path copiedLink1 = copiedInnerDir.getChild("link-1");
+ assertTrue(copiedLink1.exists());
+ assertTrue(copiedLink1.isSymbolicLink());
+ assertEquals(copiedLink1.resolveSymbolicLinks(), file4);
+
+ Path copiedDirLink = copiedInnerDir.getChild("dir-link");
+ assertTrue(copiedDirLink.exists());
+ assertTrue(copiedDirLink.isSymbolicLink());
+ assertEquals(copiedDirLink.resolveSymbolicLinks(), aDir);
+ }
+
+ // tests
+
+ @Test
+ public void testChangeModtime() throws IOException {
+ Path file = fileSystem.getPath("/my-file");
+ try {
+ BlazeTestUtils.changeModtime(file);
+ fail();
+ } catch (FileNotFoundException e) {
+ /* ok */
+ }
+ FileSystemUtils.createEmptyFile(file);
+ long prevMtime = file.getLastModifiedTime();
+ BlazeTestUtils.changeModtime(file);
+ assertFalse(prevMtime == file.getLastModifiedTime());
+ }
+
+ @Test
+ public void testCommonAncestor() {
+ assertEquals(topDir, commonAncestor(topDir, topDir));
+ assertEquals(topDir, commonAncestor(file1, file3));
+ assertEquals(topDir, commonAncestor(file1, dirLink));
+ }
+
+ @Test
+ public void testRelativePath() throws IOException {
+ createTestDirectoryTree();
+ assertEquals("file-1", relativePath(topDir, file1).getPathString());
+ assertEquals(".", relativePath(topDir, topDir).getPathString());
+ assertEquals("a-dir/inner-dir/dir-link", relativePath(topDir, dirLink).getPathString());
+ assertEquals("../file-4", relativePath(topDir, file4).getPathString());
+ assertEquals("../../../file-4", relativePath(innerDir, file4).getPathString());
+ }
+
+ private String longestPathPrefixStr(String path, String... prefixStrs) {
+ Set<PathFragment> prefixes = new HashSet<>();
+ for (String prefix : prefixStrs) {
+ prefixes.add(new PathFragment(prefix));
+ }
+ PathFragment longest = longestPathPrefix(new PathFragment(path), prefixes);
+ return longest != null ? longest.getPathString() : null;
+ }
+
+ @Test
+ public void testLongestPathPrefix() {
+ assertEquals("A", longestPathPrefixStr("A/b", "A", "B")); // simple parent
+ assertEquals("A", longestPathPrefixStr("A", "A", "B")); // self
+ assertEquals("A/B", longestPathPrefixStr("A/B/c", "A", "A/B")); // want longest
+ assertNull(longestPathPrefixStr("C/b", "A", "B")); // not found in other parents
+ assertNull(longestPathPrefixStr("A", "A/B", "B")); // not found in child
+ assertEquals("A/B/C", longestPathPrefixStr("A/B/C/d/e/f.h", "A/B/C", "B/C/d"));
+ }
+
+ @Test
+ public void testRemoveExtension_Strings() throws Exception {
+ assertEquals("foo", removeExtension("foo.c"));
+ assertEquals("a/foo", removeExtension("a/foo.c"));
+ assertEquals("a.b/foo", removeExtension("a.b/foo"));
+ assertEquals("foo", removeExtension("foo"));
+ assertEquals("foo", removeExtension("foo."));
+ }
+
+ @Test
+ public void testRemoveExtension_Paths() throws Exception {
+ assertPath("/foo", removeExtension(fileSystem.getPath("/foo.c")));
+ assertPath("/a/foo", removeExtension(fileSystem.getPath("/a/foo.c")));
+ assertPath("/a.b/foo", removeExtension(fileSystem.getPath("/a.b/foo")));
+ assertPath("/foo", removeExtension(fileSystem.getPath("/foo")));
+ assertPath("/foo", removeExtension(fileSystem.getPath("/foo.")));
+ }
+
+ private static void assertPath(String expected, PathFragment actual) {
+ assertEquals(expected, actual.getPathString());
+ }
+
+ private static void assertPath(String expected, Path actual) {
+ assertEquals(expected, actual.getPathString());
+ }
+
+ @Test
+ public void testReplaceExtension_Path() throws Exception {
+ assertPath("/foo/bar.baz",
+ FileSystemUtils.replaceExtension(fileSystem.getPath("/foo/bar"), ".baz"));
+ assertPath("/foo/bar.baz",
+ FileSystemUtils.replaceExtension(fileSystem.getPath("/foo/bar.cc"), ".baz"));
+ assertPath("/foo.baz", FileSystemUtils.replaceExtension(fileSystem.getPath("/foo/"), ".baz"));
+ assertPath("/foo.baz",
+ FileSystemUtils.replaceExtension(fileSystem.getPath("/foo.cc/"), ".baz"));
+ assertPath("/foo.baz", FileSystemUtils.replaceExtension(fileSystem.getPath("/foo"), ".baz"));
+ assertPath("/foo.baz", FileSystemUtils.replaceExtension(fileSystem.getPath("/foo.cc"), ".baz"));
+ assertPath("/.baz", FileSystemUtils.replaceExtension(fileSystem.getPath("/.cc"), ".baz"));
+ assertEquals(null, FileSystemUtils.replaceExtension(fileSystem.getPath("/"), ".baz"));
+ }
+
+ @Test
+ public void testReplaceExtension_PathFragment() throws Exception {
+ assertPath("foo/bar.baz",
+ FileSystemUtils.replaceExtension(new PathFragment("foo/bar"), ".baz"));
+ assertPath("foo/bar.baz",
+ FileSystemUtils.replaceExtension(new PathFragment("foo/bar.cc"), ".baz"));
+ assertPath("/foo/bar.baz",
+ FileSystemUtils.replaceExtension(new PathFragment("/foo/bar"), ".baz"));
+ assertPath("/foo/bar.baz",
+ FileSystemUtils.replaceExtension(new PathFragment("/foo/bar.cc"), ".baz"));
+ assertPath("foo.baz", FileSystemUtils.replaceExtension(new PathFragment("foo/"), ".baz"));
+ assertPath("foo.baz", FileSystemUtils.replaceExtension(new PathFragment("foo.cc/"), ".baz"));
+ assertPath("/foo.baz", FileSystemUtils.replaceExtension(new PathFragment("/foo/"), ".baz"));
+ assertPath("/foo.baz",
+ FileSystemUtils.replaceExtension(new PathFragment("/foo.cc/"), ".baz"));
+ assertPath("foo.baz", FileSystemUtils.replaceExtension(new PathFragment("foo"), ".baz"));
+ assertPath("foo.baz", FileSystemUtils.replaceExtension(new PathFragment("foo.cc"), ".baz"));
+ assertPath("/foo.baz", FileSystemUtils.replaceExtension(new PathFragment("/foo"), ".baz"));
+ assertPath("/foo.baz",
+ FileSystemUtils.replaceExtension(new PathFragment("/foo.cc"), ".baz"));
+ assertPath(".baz", FileSystemUtils.replaceExtension(new PathFragment(".cc"), ".baz"));
+ assertEquals(null, FileSystemUtils.replaceExtension(new PathFragment("/"), ".baz"));
+ assertEquals(null, FileSystemUtils.replaceExtension(new PathFragment(""), ".baz"));
+ assertPath("foo/bar.baz",
+ FileSystemUtils.replaceExtension(new PathFragment("foo/bar.pony"), ".baz", ".pony"));
+ assertPath("foo/bar.baz",
+ FileSystemUtils.replaceExtension(new PathFragment("foo/bar"), ".baz", ""));
+ assertEquals(null, FileSystemUtils.replaceExtension(new PathFragment(""), ".baz", ".pony"));
+ assertEquals(null,
+ FileSystemUtils.replaceExtension(new PathFragment("foo/bar.pony"), ".baz", ".unicorn"));
+ }
+
+ @Test
+ public void testAppendWithoutExtension() throws Exception {
+ assertPath("libfoo-src.jar",
+ appendWithoutExtension(new PathFragment("libfoo.jar"), "-src"));
+ assertPath("foo/libfoo-src.jar",
+ appendWithoutExtension(new PathFragment("foo/libfoo.jar"), "-src"));
+ assertPath("java/com/google/foo/libfoo-src.jar",
+ appendWithoutExtension(new PathFragment("java/com/google/foo/libfoo.jar"), "-src"));
+ assertPath("libfoo.bar-src.jar",
+ appendWithoutExtension(new PathFragment("libfoo.bar.jar"), "-src"));
+ assertPath("libfoo-src",
+ appendWithoutExtension(new PathFragment("libfoo"), "-src"));
+ assertPath("libfoo-src.jar",
+ appendWithoutExtension(new PathFragment("libfoo.jar/"), "-src"));
+ assertPath("libfoo.src.jar",
+ appendWithoutExtension(new PathFragment("libfoo.jar"), ".src"));
+ assertEquals(null, appendWithoutExtension(new PathFragment("/"), "-src"));
+ assertEquals(null, appendWithoutExtension(new PathFragment(""), "-src"));
+ }
+
+ @Test
+ public void testReplaceSegments() {
+ assertPath(
+ "poo/bar/baz.cc",
+ FileSystemUtils.replaceSegments(new PathFragment("foo/bar/baz.cc"), "foo", "poo", true));
+ assertPath(
+ "poo/poo/baz.cc",
+ FileSystemUtils.replaceSegments(new PathFragment("foo/foo/baz.cc"), "foo", "poo", true));
+ assertPath(
+ "poo/foo/baz.cc",
+ FileSystemUtils.replaceSegments(new PathFragment("foo/foo/baz.cc"), "foo", "poo", false));
+ assertPath(
+ "foo/bar/baz.cc",
+ FileSystemUtils.replaceSegments(new PathFragment("foo/bar/baz.cc"), "boo", "poo", true));
+ }
+
+ @Test
+ public void testGetWorkingDirectory() {
+ String userDir = System.getProperty("user.dir");
+
+ assertEquals(FileSystemUtils.getWorkingDirectory(fileSystem),
+ fileSystem.getPath(System.getProperty("user.dir", "/")));
+
+ System.setProperty("user.dir", "/blah/blah/blah");
+ assertEquals(FileSystemUtils.getWorkingDirectory(fileSystem),
+ fileSystem.getPath("/blah/blah/blah"));
+
+ System.setProperty("user.dir", userDir);
+ }
+
+ @Test
+ public void testResolveRelativeToFilesystemWorkingDir() {
+ PathFragment relativePath = new PathFragment("relative/path");
+ assertEquals(workingDir.getRelative(relativePath),
+ workingDir.getRelative(relativePath));
+
+ PathFragment absolutePath = new PathFragment("/absolute/path");
+ assertEquals(fileSystem.getPath(absolutePath),
+ workingDir.getRelative(absolutePath));
+ }
+
+ @Test
+ public void testTouchFileCreatesFile() throws IOException {
+ createTestDirectoryTree();
+ Path nonExistingFile = fileSystem.getPath("/previously-non-existing");
+ assertFalse(nonExistingFile.exists());
+ touchFile(nonExistingFile);
+
+ assertTrue(nonExistingFile.exists());
+ }
+
+ @Test
+ public void testTouchFileAdjustsFileTime() throws IOException {
+ createTestDirectoryTree();
+ Path testFile = file4;
+ long oldTime = testFile.getLastModifiedTime();
+ testFile.setLastModifiedTime(42);
+ touchFile(testFile);
+
+ assertTrue(testFile.getLastModifiedTime() >= oldTime);
+ }
+
+ @Test
+ public void testCopyFile() throws IOException {
+ createTestDirectoryTree();
+ Path originalFile = file1;
+ byte[] content = new byte[] { 'a', 'b', 'c', 23, 42 };
+ FileSystemUtils.writeContent(originalFile, content);
+
+ Path copyTarget = file2;
+
+ copyFile(originalFile, copyTarget);
+
+ assertTrue(Arrays.equals(content, FileSystemUtils.readContent(copyTarget)));
+ }
+
+ @Test
+ public void testReadContentWithLimit() throws IOException {
+ createTestDirectoryTree();
+ String str = "this is a test of readContentWithLimit method";
+ FileSystemUtils.writeContent(file1, StandardCharsets.ISO_8859_1, str);
+ assertEquals(readStringFromFile(file1, 0), "");
+ assertEquals(readStringFromFile(file1, 10), str.substring(0, 10));
+ assertEquals(readStringFromFile(file1, 1000000), str);
+ }
+
+ private String readStringFromFile(Path file, int limit) throws IOException {
+ byte[] bytes = FileSystemUtils.readContentWithLimit(file, limit);
+ return new String(bytes, StandardCharsets.ISO_8859_1);
+ }
+
+ @Test
+ public void testAppend() throws IOException {
+ createTestDirectoryTree();
+ FileSystemUtils.writeIsoLatin1(file1, "nobody says ");
+ FileSystemUtils.writeIsoLatin1(file1, "mary had");
+ FileSystemUtils.appendIsoLatin1(file1, "a little lamb");
+ assertEquals(
+ "mary had\na little lamb\n",
+ new String(FileSystemUtils.readContentAsLatin1(file1)));
+ }
+
+ @Test
+ public void testCopyFileAttributes() throws IOException {
+ createTestDirectoryTree();
+ Path originalFile = file1;
+ byte[] content = new byte[] { 'a', 'b', 'c', 23, 42 };
+ FileSystemUtils.writeContent(originalFile, content);
+ file1.setLastModifiedTime(12345L);
+ file1.setWritable(false);
+ file1.setExecutable(false);
+
+ Path copyTarget = file2;
+ copyFile(originalFile, copyTarget);
+
+ assertEquals(12345L, file2.getLastModifiedTime());
+ assertFalse(file2.isExecutable());
+ assertFalse(file2.isWritable());
+
+ file1.setWritable(true);
+ file1.setExecutable(true);
+
+ copyFile(originalFile, copyTarget);
+
+ assertEquals(12345L, file2.getLastModifiedTime());
+ assertTrue(file2.isExecutable());
+ assertTrue(file2.isWritable());
+
+ }
+
+ @Test
+ public void testCopyFileThrowsExceptionIfTargetCantBeDeleted() throws IOException {
+ createTestDirectoryTree();
+ Path originalFile = file1;
+ byte[] content = new byte[] { 'a', 'b', 'c', 23, 42 };
+ FileSystemUtils.writeContent(originalFile, content);
+
+ try {
+ copyFile(originalFile, aDir);
+ fail();
+ } catch (IOException ex) {
+ assertEquals("error copying file: couldn't delete destination: "
+ + aDir + " (Directory not empty)",
+ ex.getMessage());
+ }
+ }
+
+ @Test
+ public void testCopyTool() throws IOException {
+ createTestDirectoryTree();
+ Path originalFile = file1;
+ byte[] content = new byte[] { 'a', 'b', 'c', 23, 42 };
+ FileSystemUtils.writeContent(originalFile, content);
+
+ Path copyTarget = copyTool(topDir.getRelative("file-1"), aDir.getRelative("file-1"));
+
+ assertTrue(Arrays.equals(content, FileSystemUtils.readContent(copyTarget)));
+ assertEquals(file1.isWritable(), copyTarget.isWritable());
+ assertEquals(file1.isExecutable(), copyTarget.isExecutable());
+ assertEquals(file1.getLastModifiedTime(), copyTarget.getLastModifiedTime());
+ }
+
+ @Test
+ public void testCopyTreesBelow() throws IOException {
+ createTestDirectoryTree();
+ Path toPath = fileSystem.getPath("/copy-here");
+ toPath.createDirectory();
+
+ FileSystemUtils.copyTreesBelow(topDir, toPath);
+ checkTestDirectoryTreesBelow(toPath);
+ }
+
+ @Test
+ public void testCopyTreesBelowWithOverriding() throws IOException {
+ createTestDirectoryTree();
+ Path toPath = fileSystem.getPath("/copy-here");
+ toPath.createDirectory();
+ toPath.getChild("file-2");
+
+ FileSystemUtils.copyTreesBelow(topDir, toPath);
+ checkTestDirectoryTreesBelow(toPath);
+ }
+
+ @Test
+ public void testCopyTreesBelowToSubtree() throws IOException {
+ createTestDirectoryTree();
+ try {
+ FileSystemUtils.copyTreesBelow(topDir, aDir);
+ fail("Should not be able to copy a directory to a subdir");
+ } catch (IllegalArgumentException expected) {
+ assertEquals("/top-dir/a-dir is a subdirectory of /top-dir", expected.getMessage());
+ }
+ }
+
+ @Test
+ public void testCopyFileAsDirectoryTree() throws IOException {
+ createTestDirectoryTree();
+ try {
+ FileSystemUtils.copyTreesBelow(file1, aDir);
+ fail("Should not be able to copy a file with copyDirectory method");
+ } catch (IOException expected) {
+ assertEquals("/top-dir/file-1 (Not a directory)", expected.getMessage());
+ }
+ }
+
+ @Test
+ public void testCopyTreesBelowToFile() throws IOException {
+ createTestDirectoryTree();
+ Path copyDir = fileSystem.getPath("/my-dir");
+ Path copySubDir = fileSystem.getPath("/my-dir/subdir");
+ FileSystemUtils.createDirectoryAndParents(copySubDir);
+ try {
+ FileSystemUtils.copyTreesBelow(copyDir, file4);
+ fail("Should not be able to copy a directory to a file");
+ } catch (IOException expected) {
+ assertEquals("/file-4 (Not a directory)", expected.getMessage());
+ }
+ }
+
+ @Test
+ public void testCopyTreesBelowFromUnexistingDir() throws IOException {
+ createTestDirectoryTree();
+
+ try {
+ Path unexistingDir = fileSystem.getPath("/unexisting-dir");
+ FileSystemUtils.copyTreesBelow(unexistingDir, aDir);
+ fail("Should not be able to copy from an unexisting path");
+ } catch (FileNotFoundException expected) {
+ assertEquals("/unexisting-dir (No such file or directory)", expected.getMessage());
+ }
+ }
+
+ @Test
+ public void testTraverseTree() throws IOException {
+ createTestDirectoryTree();
+
+ Collection<Path> paths = traverseTree(topDir, new Predicate<Path>() {
+ @Override
+ public boolean apply(Path p) {
+ return !p.getPathString().contains("a-dir");
+ }
+ });
+ assertThat(paths).containsExactly(file1, file2);
+ }
+
+ @Test
+ public void testTraverseTreeDeep() throws IOException {
+ createTestDirectoryTree();
+
+ Collection<Path> paths = traverseTree(topDir,
+ Predicates.alwaysTrue());
+ assertThat(paths).containsExactly(aDir,
+ file3,
+ innerDir,
+ link1,
+ file1,
+ file2,
+ dirLink);
+ }
+
+ @Test
+ public void testTraverseTreeLinkDir() throws IOException {
+ // Use a new little tree for this test:
+ // top-dir/
+ // dir-link2 => linked-dir
+ // linked-dir/
+ // file
+ topDir = fileSystem.getPath("/top-dir");
+ Path dirLink2 = fileSystem.getPath("/top-dir/dir-link2");
+ Path linkedDir = fileSystem.getPath("/linked-dir");
+ Path linkedDirFile = fileSystem.getPath("/top-dir/dir-link2/file");
+
+ topDir.createDirectory();
+ linkedDir.createDirectory();
+ dirLink2.createSymbolicLink(linkedDir); // simple symlink
+ FileSystemUtils.createEmptyFile(linkedDirFile); // created through the link
+
+ // traverseTree doesn't follow links:
+ Collection<Path> paths = traverseTree(topDir, Predicates.alwaysTrue());
+ assertThat(paths).containsExactly(dirLink2);
+
+ paths = traverseTree(linkedDir, Predicates.alwaysTrue());
+ assertThat(paths).containsExactly(fileSystem.getPath("/linked-dir/file"));
+ }
+
+ @Test
+ public void testDeleteTreeCommandDeletesTree() throws IOException {
+ createTestDirectoryTree();
+ Path toDelete = topDir;
+ deleteTree(toDelete);
+
+ assertTrue(file4.exists());
+ assertFalse(topDir.exists());
+ assertFalse(file1.exists());
+ assertFalse(file2.exists());
+ assertFalse(aDir.exists());
+ assertFalse(file3.exists());
+ }
+
+ @Test
+ public void testDeleteTreeCommandsDeletesUnreadableDirectories() throws IOException {
+ createTestDirectoryTree();
+ Path toDelete = topDir;
+
+ try {
+ aDir.setReadable(false);
+ } catch (UnsupportedOperationException e) {
+ // For file systems that do not support setting readable attribute to
+ // false, this test is simply skipped.
+
+ return;
+ }
+
+ deleteTree(toDelete);
+ assertFalse(topDir.exists());
+ assertFalse(aDir.exists());
+
+ }
+
+ @Test
+ public void testDeleteTreeCommandDoesNotFollowLinksOut() throws IOException {
+ createTestDirectoryTree();
+ Path toDelete = topDir;
+ Path outboundLink = fileSystem.getPath("/top-dir/outbound-link");
+ outboundLink.createSymbolicLink(file4);
+
+ deleteTree(toDelete);
+
+ assertTrue(file4.exists());
+ assertFalse(topDir.exists());
+ assertFalse(file1.exists());
+ assertFalse(file2.exists());
+ assertFalse(aDir.exists());
+ assertFalse(file3.exists());
+ }
+
+ @Test
+ public void testDeleteTreesBelowNotPrefixed() throws IOException {
+ createTestDirectoryTree();
+ deleteTreesBelowNotPrefixed(topDir, new String[] { "file-"});
+ assertTrue(file1.exists());
+ assertTrue(file2.exists());
+ assertFalse(aDir.exists());
+ }
+
+ @Test
+ public void testCreateDirectories() throws IOException {
+ Path mainPath = fileSystem.getPath("/some/where/deep/in/the/hierarchy");
+ assertTrue(createDirectoryAndParents(mainPath));
+ assertTrue(mainPath.exists());
+ assertFalse(createDirectoryAndParents(mainPath));
+ }
+
+ @Test
+ public void testCreateDirectoriesWhenAncestorIsFile() throws IOException {
+ Path somewhereDeepIn = fileSystem.getPath("/somewhere/deep/in");
+ assertTrue(createDirectoryAndParents(somewhereDeepIn.getParentDirectory()));
+ FileSystemUtils.createEmptyFile(somewhereDeepIn);
+ Path theHierarchy = somewhereDeepIn.getChild("the-hierarchy");
+ try {
+ createDirectoryAndParents(theHierarchy);
+ fail();
+ } catch (IOException e) {
+ assertEquals("/somewhere/deep/in (Not a directory)", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testCreateDirectoriesWhenSymlinkToDir() throws IOException {
+ Path somewhereDeepIn = fileSystem.getPath("/somewhere/deep/in");
+ assertTrue(createDirectoryAndParents(somewhereDeepIn));
+ Path realDir = fileSystem.getPath("/real/dir");
+ assertTrue(createDirectoryAndParents(realDir));
+
+ Path theHierarchy = somewhereDeepIn.getChild("the-hierarchy");
+ theHierarchy.createSymbolicLink(realDir);
+
+ assertFalse(createDirectoryAndParents(theHierarchy));
+ }
+
+ @Test
+ public void testCreateDirectoriesWhenSymlinkEmbedded() throws IOException {
+ Path somewhereDeepIn = fileSystem.getPath("/somewhere/deep/in");
+ assertTrue(createDirectoryAndParents(somewhereDeepIn));
+ Path realDir = fileSystem.getPath("/real/dir");
+ assertTrue(createDirectoryAndParents(realDir));
+
+ Path the = somewhereDeepIn.getChild("the");
+ the.createSymbolicLink(realDir);
+
+ Path theHierarchy = somewhereDeepIn.getChild("hierarchy");
+ assertTrue(createDirectoryAndParents(theHierarchy));
+ }
+
+ PathFragment createPkg(Path rootA, Path rootB, String pkg) throws IOException {
+ if (rootA != null) {
+ createDirectoryAndParents(rootA.getRelative(pkg));
+ FileSystemUtils.createEmptyFile(rootA.getRelative(pkg).getChild("file"));
+ }
+ if (rootB != null) {
+ createDirectoryAndParents(rootB.getRelative(pkg));
+ FileSystemUtils.createEmptyFile(rootB.getRelative(pkg).getChild("file"));
+ }
+ return new PathFragment(pkg);
+ }
+
+ void assertLinksTo(Path fromRoot, Path toRoot, String relpart) throws IOException {
+ assertTrue(fromRoot.getRelative(relpart).isSymbolicLink());
+ assertEquals(toRoot.getRelative(relpart).asFragment(),
+ fromRoot.getRelative(relpart).readSymbolicLink());
+ }
+
+ void assertIsDir(Path root, String relpart) {
+ assertTrue(root.getRelative(relpart).isDirectory(Symlinks.NOFOLLOW));
+ }
+
+ void dumpTree(Path root, PrintStream out) throws IOException {
+ out.println("\n" + root);
+ for (Path p : FileSystemUtils.traverseTree(root, Predicates.alwaysTrue())) {
+ if (p.isDirectory(Symlinks.NOFOLLOW)) {
+ out.println(" " + p + "/");
+ } else if (p.isSymbolicLink()) {
+ out.println(" " + p + " => " + p.readSymbolicLink());
+ } else {
+ out.println(" " + p + " [" + p.resolveSymbolicLinks() + "]");
+ }
+ }
+ }
+
+ @Test
+ public void testPlantLinkForest() throws IOException {
+ Path rootA = fileSystem.getPath("/A");
+ Path rootB = fileSystem.getPath("/B");
+
+ ImmutableMap<PathFragment, Path> packageRootMap = ImmutableMap.<PathFragment, Path>builder()
+ .put(createPkg(rootA, rootB, "pkgA"), rootA)
+ .put(createPkg(rootA, rootB, "dir1/pkgA"), rootA)
+ .put(createPkg(rootA, rootB, "dir1/pkgB"), rootB)
+ .put(createPkg(rootA, rootB, "dir2/pkg"), rootA)
+ .put(createPkg(rootA, rootB, "dir2/pkg/pkg"), rootB)
+ .put(createPkg(rootA, rootB, "pkgB"), rootB)
+ .put(createPkg(rootA, rootB, "pkgB/dir/pkg"), rootA)
+ .put(createPkg(rootA, rootB, "pkgB/pkg"), rootA)
+ .put(createPkg(rootA, rootB, "pkgB/pkg/pkg"), rootA)
+ .build();
+ createPkg(rootA, rootB, "pkgB/dir"); // create a file in there
+
+ //dumpTree(rootA, System.err);
+ //dumpTree(rootB, System.err);
+
+ Path linkRoot = fileSystem.getPath("/linkRoot");
+ createDirectoryAndParents(linkRoot);
+ plantLinkForest(packageRootMap, linkRoot);
+
+ //dumpTree(linkRoot, System.err);
+
+ assertLinksTo(linkRoot, rootA, "pkgA");
+ assertIsDir(linkRoot, "dir1");
+ assertLinksTo(linkRoot, rootA, "dir1/pkgA");
+ assertLinksTo(linkRoot, rootB, "dir1/pkgB");
+ assertIsDir(linkRoot, "dir2");
+ assertIsDir(linkRoot, "dir2/pkg");
+ assertLinksTo(linkRoot, rootA, "dir2/pkg/file");
+ assertLinksTo(linkRoot, rootB, "dir2/pkg/pkg");
+ assertIsDir(linkRoot, "pkgB");
+ assertIsDir(linkRoot, "pkgB/dir");
+ assertLinksTo(linkRoot, rootB, "pkgB/dir/file");
+ assertLinksTo(linkRoot, rootA, "pkgB/dir/pkg");
+ assertLinksTo(linkRoot, rootA, "pkgB/pkg");
+ }
+
+ @Test
+ public void testWriteIsoLatin1() throws Exception {
+ Path file = fileSystem.getPath("/does/not/exist/yet.txt");
+ FileSystemUtils.writeIsoLatin1(file, "Line 1", "Line 2", "Line 3");
+ String expected = "Line 1\nLine 2\nLine 3\n";
+ String actual = new String(FileSystemUtils.readContentAsLatin1(file));
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testWriteLinesAs() throws Exception {
+ Path file = fileSystem.getPath("/does/not/exist/yet.txt");
+ FileSystemUtils.writeLinesAs(file, UTF_8, "\u00F6"); // an oe umlaut
+ byte[] expected = new byte[] {(byte) 0xC3, (byte) 0xB6, 0x0A};//"\u00F6\n";
+ byte[] actual = FileSystemUtils.readContent(file);
+ assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testGetFileSystem() throws Exception {
+ Path mountTable = fileSystem.getPath("/proc/mounts");
+ FileSystemUtils.writeIsoLatin1(mountTable,
+ "/dev/sda1 / ext2 blah 0 0",
+ "/dev/mapper/_dev_sda6 /usr/local/google ext3 blah 0 0",
+ "devshm /dev/shm tmpfs blah 0 0",
+ "/dev/fuse /fuse/mnt fuse blah 0 0",
+ "mtvhome22.nfs:/vol/mtvhome22/johndoe /home/johndoe nfs blah 0 0",
+ "/dev/foo /foo dummy_foo blah 0 0",
+ "/dev/foobar /foobar dummy_foobar blah 0 0",
+ "proc proc proc rw,noexec,nosuid,nodev 0 0");
+ Path path = fileSystem.getPath("/usr/local/google/_blaze");
+ FileSystemUtils.createDirectoryAndParents(path);
+ assertEquals("ext3", FileSystemUtils.getFileSystem(path));
+
+ // Should match the root "/"
+ path = fileSystem.getPath("/usr/local/tmp");
+ FileSystemUtils.createDirectoryAndParents(path);
+ assertEquals("ext2", FileSystemUtils.getFileSystem(path));
+
+ // Make sure we don't consider /foobar matches /foo
+ path = fileSystem.getPath("/foo");
+ FileSystemUtils.createDirectoryAndParents(path);
+ assertEquals("dummy_foo", FileSystemUtils.getFileSystem(path));
+ path = fileSystem.getPath("/foobar");
+ FileSystemUtils.createDirectoryAndParents(path);
+ assertEquals("dummy_foobar", FileSystemUtils.getFileSystem(path));
+
+ path = fileSystem.getPath("/dev/shm/blaze");
+ FileSystemUtils.createDirectoryAndParents(path);
+ assertEquals("tmpfs", FileSystemUtils.getFileSystem(path));
+
+ Path fusePath = fileSystem.getPath("/fuse/mnt/tmp");
+ FileSystemUtils.createDirectoryAndParents(fusePath);
+ assertEquals("fuse", FileSystemUtils.getFileSystem(fusePath));
+
+ // Create a symlink and make sure it gives the file system of the symlink target.
+ path = fileSystem.getPath("/usr/local/google/_blaze/out");
+ path.createSymbolicLink(fusePath);
+ assertEquals("fuse", FileSystemUtils.getFileSystem(path));
+
+ // Non existent path should return "unknown"
+ path = fileSystem.getPath("/does/not/exist");
+ assertEquals("unknown", FileSystemUtils.getFileSystem(path));
+ }
+
+ @Test
+ public void testStartsWithAnySuccess() throws Exception {
+ PathFragment a = new PathFragment("a");
+ assertTrue(FileSystemUtils.startsWithAny(a,
+ Arrays.asList(new PathFragment("b"), new PathFragment("a"))));
+ }
+
+ @Test
+ public void testStartsWithAnyNotFound() throws Exception {
+ PathFragment a = new PathFragment("a");
+ assertFalse(FileSystemUtils.startsWithAny(a,
+ Arrays.asList(new PathFragment("b"), new PathFragment("c"))));
+ }
+
+ @Test
+ public void testIterateLines() throws Exception {
+ Path file = fileSystem.getPath("/test.txt");
+ FileSystemUtils.writeContent(file, ISO_8859_1, "a\nb");
+ assertEquals(Arrays.asList("a", "b"),
+ Lists.newArrayList(FileSystemUtils.iterateLinesAsLatin1(file)));
+
+ FileSystemUtils.writeContent(file, ISO_8859_1, "a\rb");
+ assertEquals(Arrays.asList("a", "b"),
+ Lists.newArrayList(FileSystemUtils.iterateLinesAsLatin1(file)));
+
+ FileSystemUtils.writeContent(file, ISO_8859_1, "a\r\nb");
+ assertEquals(Arrays.asList("a", "b"),
+ Lists.newArrayList(FileSystemUtils.iterateLinesAsLatin1(file)));
+ }
+
+ @Test
+ public void testEnsureSymbolicLinkDoesNotMakeUnnecessaryChanges() throws Exception {
+ PathFragment target = new PathFragment("/b");
+ Path file = fileSystem.getPath("/a");
+ file.createSymbolicLink(target);
+ long prevTimeMillis = clock.currentTimeMillis();
+ clock.advanceMillis(1000);
+ FileSystemUtils.ensureSymbolicLink(file, target);
+ long timestamp = file.getLastModifiedTime(Symlinks.NOFOLLOW);
+ assertTrue(timestamp == prevTimeMillis);
+ }
+}