blob: f9f485032015da553acc5b9b0cc9fa34d48bc02e [file] [log] [blame]
// Copyright 2014 The Bazel Authors. 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.moveFile;
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.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 java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* This class tests the file system utilities.
*/
@RunWith(JUnit4.class)
public class FileSystemUtilsTest {
private ManualClock clock;
private FileSystem fileSystem;
private Path workingDir;
@Before
public final void initializeFileSystem() throws Exception {
clock = new ManualClock();
fileSystem = new InMemoryFileSystem(clock);
workingDir = fileSystem.getPath("/workingDir");
workingDir.createDirectory();
}
Path topDir;
Path file1;
Path file2;
Path aDir;
Path bDir;
Path file3;
Path innerDir;
Path link1;
Path dirLink;
Path file4;
Path file5;
/*
* 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 => b-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");
bDir = fileSystem.getPath("/top-dir/b-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");
file5 = fileSystem.getPath("/top-dir/b-dir/file-5");
topDir.createDirectory();
FileSystemUtils.createEmptyFile(file1);
FileSystemUtils.createEmptyFile(file2);
aDir.createDirectory();
bDir.createDirectory();
FileSystemUtils.createEmptyFile(file3);
innerDir.createDirectory();
link1.createSymbolicLink(file4); // simple symlink
dirLink.createSymbolicLink(bDir);
FileSystemUtils.createEmptyFile(file4);
FileSystemUtils.createEmptyFile(file5);
}
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();
assertThat(aDirEntries).hasSize(2);
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());
assertFalse(copiedLink1.isSymbolicLink());
Path copiedDirLink = copiedInnerDir.getChild("dir-link");
assertTrue(copiedDirLink.exists());
assertTrue(copiedDirLink.isDirectory());
assertTrue(copiedDirLink.getChild("file-5").exists());
}
// 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());
}
@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"));
assertNull(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"));
assertNull(FileSystemUtils.replaceExtension(new PathFragment("/"), ".baz"));
assertNull(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", ""));
assertNull(FileSystemUtils.replaceExtension(new PathFragment(""), ".baz", ".pony"));
assertNull(
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"));
assertNull(appendWithoutExtension(new PathFragment("/"), "-src"));
assertNull(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);
assertThat(testFile.getLastModifiedTime()).isAtLeast(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 testMoveFile() throws IOException {
createTestDirectoryTree();
Path originalFile = file1;
byte[] content = new byte[] { 'a', 'b', 'c', 23, 42 };
FileSystemUtils.writeContent(originalFile, content);
Path moveTarget = file2;
moveFile(originalFile, moveTarget);
assertTrue(Arrays.equals(content, FileSystemUtils.readContent(moveTarget)));
assertFalse(originalFile.exists());
}
@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) {
assertThat(ex).hasMessage(
"error copying file: couldn't delete destination: " + aDir + " (Directory not empty)");
}
}
@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) {
assertThat(expected).hasMessage("/top-dir/a-dir is a subdirectory of /top-dir");
}
}
@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) {
assertThat(expected).hasMessage("/top-dir/file-1 (Not a directory)");
}
}
@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) {
assertThat(expected).hasMessage("/file-4 (Not a directory)");
}
}
@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) {
assertThat(expected).hasMessage("/unexisting-dir (No such file or directory)");
}
}
@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, bDir, file5);
}
@Test
public void testTraverseTreeDeep() throws IOException {
createTestDirectoryTree();
Collection<Path> paths = traverseTree(topDir,
Predicates.alwaysTrue());
assertThat(paths).containsExactly(aDir,
file3,
innerDir,
link1,
file1,
file2,
dirLink,
bDir,
file5);
}
@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 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) {
assertThat(e).hasMessage("/somewhere/deep/in (Not a directory)");
}
}
@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));
}
@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 testUpdateContent() throws Exception {
Path file = fileSystem.getPath("/test.txt");
clock.advanceMillis(1000);
byte[] content = new byte[] { 'a', 'b', 'c', 23, 42 };
FileSystemUtils.maybeUpdateContent(file, content);
byte[] actual = FileSystemUtils.readContent(file);
assertArrayEquals(content, actual);
FileStatus stat = file.stat();
assertEquals(1000, stat.getLastChangeTime());
assertEquals(1000, stat.getLastModifiedTime());
clock.advanceMillis(1000);
// Update with same contents; should not write anything.
FileSystemUtils.maybeUpdateContent(file, content);
assertArrayEquals(content, actual);
stat = file.stat();
assertEquals(1000, stat.getLastChangeTime());
assertEquals(1000, stat.getLastModifiedTime());
clock.advanceMillis(1000);
// Update with different contents; file should be rewritten.
content[0] = 'b';
file.chmod(0400); // Protect the file to ensure we can rewrite it.
FileSystemUtils.maybeUpdateContent(file, content);
actual = FileSystemUtils.readContent(file);
assertArrayEquals(content, actual);
stat = file.stat();
assertEquals(3000, stat.getLastChangeTime());
assertEquals(3000, stat.getLastModifiedTime());
}
@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);
assertEquals(prevTimeMillis, timestamp);
}
@Test
public void testCreateHardLinkForFile_Success() throws Exception {
/* Original file exists and link file does not exist */
Path originalPath = workingDir.getRelative("original");
Path linkPath = workingDir.getRelative("link");
FileSystemUtils.createEmptyFile(originalPath);
FileSystemUtils.createHardLink(linkPath, originalPath);
assertTrue(originalPath.exists());
assertTrue(linkPath.exists());
assertEquals(
fileSystem.stat(originalPath, false).getNodeId(),
fileSystem.stat(linkPath, false).getNodeId());
}
@Test
public void testCreateHardLinkForEmptyDirectory_Success() throws Exception {
Path originalDir = workingDir.getRelative("originalDir");
Path linkPath = workingDir.getRelative("link");
FileSystemUtils.createDirectoryAndParents(originalDir);
/* Original directory is empty, no link to be created. */
FileSystemUtils.createHardLink(linkPath, originalDir);
assertFalse(linkPath.exists());
}
@Test
public void testCreateHardLinkForNonEmptyDirectory_Success() throws Exception {
/* Test when original path is a directory */
Path originalDir = workingDir.getRelative("originalDir");
Path linkPath = workingDir.getRelative("link");
Path originalPath1 = originalDir.getRelative("original1");
Path originalPath2 = originalDir.getRelative("original2");
Path originalPath3 = originalDir.getRelative("original3");
Path linkPath1 = linkPath.getRelative("original1");
Path linkPath2 = linkPath.getRelative("original2");
Path linkPath3 = linkPath.getRelative("original3");
FileSystemUtils.createDirectoryAndParents(originalDir);
FileSystemUtils.createEmptyFile(originalPath1);
FileSystemUtils.createEmptyFile(originalPath2);
FileSystemUtils.createEmptyFile(originalPath3);
/* Three link files created under linkPath */
FileSystemUtils.createHardLink(linkPath, originalDir);
assertTrue(linkPath.exists());
assertTrue(linkPath1.exists());
assertTrue(linkPath2.exists());
assertTrue(linkPath3.exists());
assertEquals(
fileSystem.stat(originalPath1, false).getNodeId(),
fileSystem.stat(linkPath1, false).getNodeId());
assertEquals(
fileSystem.stat(originalPath2, false).getNodeId(),
fileSystem.stat(linkPath2, false).getNodeId());
assertEquals(
fileSystem.stat(originalPath3, false).getNodeId(),
fileSystem.stat(linkPath3, false).getNodeId());
}
}