// Copyright 2016 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 com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.testutil.TestSpec; import com.google.devtools.build.lib.util.OS; import com.google.devtools.build.lib.windows.util.WindowsTestUtil; import java.io.File; import java.nio.file.Files; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link WindowsFileSystem}. */ @RunWith(JUnit4.class) @TestSpec(localOnly = true, supportedOs = OS.WINDOWS) public class WindowsFileSystemTest { private String scratchRoot; private WindowsTestUtil testUtil; private WindowsFileSystem fs; @Before public void loadJni() throws Exception { WindowsTestUtil.loadJni(); scratchRoot = new File(System.getenv("TEST_TMPDIR")).getAbsolutePath() + "/x"; testUtil = new WindowsTestUtil(scratchRoot); fs = new WindowsFileSystem(); cleanupScratchDir(); } @After public void cleanupScratchDir() throws Exception { testUtil.deleteAllUnder(""); } @Test public void testCanWorkWithJunctionSymlinks() throws Exception { testUtil.scratchFile("dir\\hello.txt", "hello"); testUtil.scratchDir("non_existent"); testUtil.createJunctions(ImmutableMap.of("junc", "dir", "junc_bad", "non_existent")); Path juncPath = testUtil.createVfsPath(fs, "junc"); Path dirPath = testUtil.createVfsPath(fs, "dir"); Path juncBadPath = testUtil.createVfsPath(fs, "junc_bad"); Path nonExistentPath = testUtil.createVfsPath(fs, "non_existent"); // Test junction creation. assertThat(fs.exists(juncPath, /* followSymlinks */ false)).isTrue(); assertThat(fs.exists(dirPath, /* followSymlinks */ false)).isTrue(); assertThat(fs.exists(juncBadPath, /* followSymlinks */ false)).isTrue(); assertThat(fs.exists(nonExistentPath, /* followSymlinks */ false)).isTrue(); // Test recognizing and dereferencing a directory junction. assertThat(fs.isSymbolicLink(juncPath)).isTrue(); assertThat(fs.isDirectory(juncPath, /* followSymlinks */ true)).isTrue(); assertThat(fs.isDirectory(juncPath, /* followSymlinks */ false)).isFalse(); assertThat(fs.getDirectoryEntries(juncPath)) .containsExactly(testUtil.createVfsPath(fs, "junc\\hello.txt")); // Test deleting a directory junction. assertThat(fs.delete(juncPath)).isTrue(); assertThat(fs.exists(juncPath, /* followSymlinks */ false)).isFalse(); // Test recognizing a dangling directory junction. assertThat(fs.delete(nonExistentPath)).isTrue(); assertThat(fs.exists(nonExistentPath, /* followSymlinks */ false)).isFalse(); assertThat(fs.exists(juncBadPath, /* followSymlinks */ false)).isTrue(); // TODO(bazel-team): fix https://github.com/bazelbuild/bazel/issues/1690 and uncomment the // assertion below. //assertThat(fs.isSymbolicLink(juncBadPath)).isTrue(); assertThat(fs.isDirectory(juncBadPath, /* followSymlinks */ true)).isFalse(); assertThat(fs.isDirectory(juncBadPath, /* followSymlinks */ false)).isFalse(); // Test deleting a dangling junction. assertThat(fs.delete(juncBadPath)).isTrue(); assertThat(fs.exists(juncBadPath, /* followSymlinks */ false)).isFalse(); } @Test public void testMockJunctionCreation() throws Exception { String root = testUtil.scratchDir("dir").getParent().toString(); testUtil.scratchFile("dir/file.txt", "hello"); testUtil.createJunctions(ImmutableMap.of("junc", "dir")); String[] children = new File(root + "/junc").list(); assertThat(children).isNotNull(); assertThat(children).hasLength(1); assertThat(Arrays.asList(children)).containsExactly("file.txt"); } @Test public void testIsJunction() throws Exception { final Map junctions = new HashMap<>(); junctions.put("shrtpath/a", "shrttrgt"); junctions.put("shrtpath/b", "longtargetpath"); junctions.put("shrtpath/c", "longta~1"); junctions.put("longlinkpath/a", "shrttrgt"); junctions.put("longlinkpath/b", "longtargetpath"); junctions.put("longlinkpath/c", "longta~1"); junctions.put("abbrev~1/a", "shrttrgt"); junctions.put("abbrev~1/b", "longtargetpath"); junctions.put("abbrev~1/c", "longta~1"); String root = testUtil.scratchDir("shrtpath").getParent().toAbsolutePath().toString(); testUtil.scratchDir("longlinkpath"); testUtil.scratchDir("abbreviated"); testUtil.scratchDir("control/a"); testUtil.scratchDir("control/b"); testUtil.scratchDir("control/c"); testUtil.scratchFile("shrttrgt/file1.txt", "hello"); testUtil.scratchFile("longtargetpath/file2.txt", "hello"); testUtil.createJunctions(junctions); assertThat(WindowsFileSystem.isJunction(new File(root, "shrtpath/a").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "shrtpath/b").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "shrtpath/c").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "longlinkpath/a").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "longlinkpath/b").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "longlinkpath/c").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "longli~1/a").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "longli~1/b").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "longli~1/c").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "abbreviated/a").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "abbreviated/b").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "abbreviated/c").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "abbrev~1/a").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "abbrev~1/b").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "abbrev~1/c").toPath())).isTrue(); assertThat(WindowsFileSystem.isJunction(new File(root, "control/a").toPath())).isFalse(); assertThat(WindowsFileSystem.isJunction(new File(root, "control/b").toPath())).isFalse(); assertThat(WindowsFileSystem.isJunction(new File(root, "control/c").toPath())).isFalse(); assertThat(WindowsFileSystem.isJunction(new File(root, "shrttrgt/file1.txt").toPath())) .isFalse(); assertThat(WindowsFileSystem.isJunction(new File(root, "longtargetpath/file2.txt").toPath())) .isFalse(); assertThat(WindowsFileSystem.isJunction(new File(root, "longta~1/file2.txt").toPath())) .isFalse(); assertThat(WindowsFileSystem.isJunction(new File(root, "non-existent").toPath())).isFalse(); assertThat(Arrays.asList(new File(root + "/shrtpath/a").list())).containsExactly("file1.txt"); assertThat(Arrays.asList(new File(root + "/shrtpath/b").list())).containsExactly("file2.txt"); assertThat(Arrays.asList(new File(root + "/shrtpath/c").list())).containsExactly("file2.txt"); assertThat(Arrays.asList(new File(root + "/longlinkpath/a").list())) .containsExactly("file1.txt"); assertThat(Arrays.asList(new File(root + "/longlinkpath/b").list())) .containsExactly("file2.txt"); assertThat(Arrays.asList(new File(root + "/longlinkpath/c").list())) .containsExactly("file2.txt"); assertThat(Arrays.asList(new File(root + "/abbreviated/a").list())) .containsExactly("file1.txt"); assertThat(Arrays.asList(new File(root + "/abbreviated/b").list())) .containsExactly("file2.txt"); assertThat(Arrays.asList(new File(root + "/abbreviated/c").list())) .containsExactly("file2.txt"); } @Test public void testIsJunctionIsTrueForDanglingJunction() throws Exception { java.nio.file.Path helloPath = testUtil.scratchFile("target\\hello.txt", "hello"); testUtil.createJunctions(ImmutableMap.of("link", "target")); File linkPath = new File(helloPath.getParent().getParent().toFile(), "link"); assertThat(Arrays.asList(linkPath.list())).containsExactly("hello.txt"); assertThat(WindowsFileSystem.isJunction(linkPath.toPath())).isTrue(); assertThat(helloPath.toFile().delete()).isTrue(); assertThat(helloPath.getParent().toFile().delete()).isTrue(); assertThat(helloPath.getParent().toFile().exists()).isFalse(); assertThat(Arrays.asList(linkPath.getParentFile().list())).containsExactly("link"); assertThat(WindowsFileSystem.isJunction(linkPath.toPath())).isTrue(); assertThat( Files.exists( linkPath.toPath(), WindowsFileSystem.symlinkOpts(/* followSymlinks */ false))) .isTrue(); assertThat( Files.exists( linkPath.toPath(), WindowsFileSystem.symlinkOpts(/* followSymlinks */ true))) .isFalse(); } }