Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 1 | // Copyright 2016 The Bazel Authors. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
Ulf Adams | 8afbd3c | 2017-02-28 10:42:48 +0000 | [diff] [blame] | 15 | package com.google.devtools.build.lib.windows; |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 16 | |
| 17 | import static com.google.common.truth.Truth.assertThat; |
Ulf Adams | 8afbd3c | 2017-02-28 10:42:48 +0000 | [diff] [blame] | 18 | import static com.google.devtools.build.lib.windows.WindowsFileSystem.SHORT_NAME_MATCHER; |
lberki | 4a45ea8 | 2017-06-01 10:05:42 +0200 | [diff] [blame] | 19 | import static org.junit.Assert.fail; |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 20 | |
Laszlo Csomor | 81f92fe | 2017-02-15 16:08:45 +0000 | [diff] [blame] | 21 | import com.google.common.base.Function; |
Laszlo Csomor | 8679e4c | 2017-01-03 15:21:08 +0000 | [diff] [blame] | 22 | import com.google.common.base.Predicate; |
Laszlo Csomor | 81f92fe | 2017-02-15 16:08:45 +0000 | [diff] [blame] | 23 | import com.google.common.collect.ImmutableList; |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 24 | import com.google.common.collect.ImmutableMap; |
Laszlo Csomor | 81f92fe | 2017-02-15 16:08:45 +0000 | [diff] [blame] | 25 | import com.google.common.collect.Iterables; |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 26 | import com.google.devtools.build.lib.testutil.TestSpec; |
| 27 | import com.google.devtools.build.lib.util.OS; |
Ulf Adams | 8afbd3c | 2017-02-28 10:42:48 +0000 | [diff] [blame] | 28 | import com.google.devtools.build.lib.vfs.Path; |
| 29 | import com.google.devtools.build.lib.vfs.PathFragment; |
| 30 | import com.google.devtools.build.lib.vfs.Symlinks; |
| 31 | import com.google.devtools.build.lib.windows.WindowsFileSystem.WindowsPath; |
Laszlo Csomor | 13f9226 | 2017-06-30 16:22:41 +0200 | [diff] [blame] | 32 | import com.google.devtools.build.lib.windows.jni.WindowsFileOperations; |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 33 | import com.google.devtools.build.lib.windows.util.WindowsTestUtil; |
| 34 | import java.io.File; |
Laszlo Csomor | fe7e57e | 2016-12-21 16:02:51 +0000 | [diff] [blame] | 35 | import java.io.IOException; |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 36 | import java.nio.file.Files; |
Laszlo Csomor | 8679e4c | 2017-01-03 15:21:08 +0000 | [diff] [blame] | 37 | import java.util.ArrayList; |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 38 | import java.util.Arrays; |
| 39 | import java.util.HashMap; |
Laszlo Csomor | 8679e4c | 2017-01-03 15:21:08 +0000 | [diff] [blame] | 40 | import java.util.List; |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 41 | import java.util.Map; |
| 42 | import org.junit.After; |
| 43 | import org.junit.Before; |
| 44 | import org.junit.Test; |
| 45 | import org.junit.runner.RunWith; |
| 46 | import org.junit.runners.JUnit4; |
| 47 | |
| 48 | /** Unit tests for {@link WindowsFileSystem}. */ |
| 49 | @RunWith(JUnit4.class) |
| 50 | @TestSpec(localOnly = true, supportedOs = OS.WINDOWS) |
| 51 | public class WindowsFileSystemTest { |
| 52 | |
| 53 | private String scratchRoot; |
| 54 | private WindowsTestUtil testUtil; |
| 55 | private WindowsFileSystem fs; |
| 56 | |
| 57 | @Before |
| 58 | public void loadJni() throws Exception { |
Yun Peng | 6a4247b | 2017-10-24 14:36:10 +0200 | [diff] [blame] | 59 | scratchRoot = new File(System.getenv("TEST_TMPDIR"), "x").getAbsolutePath(); |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 60 | testUtil = new WindowsTestUtil(scratchRoot); |
| 61 | fs = new WindowsFileSystem(); |
| 62 | cleanupScratchDir(); |
| 63 | } |
| 64 | |
| 65 | @After |
| 66 | public void cleanupScratchDir() throws Exception { |
| 67 | testUtil.deleteAllUnder(""); |
| 68 | } |
| 69 | |
| 70 | @Test |
Ulf Adams | 8afbd3c | 2017-02-28 10:42:48 +0000 | [diff] [blame] | 71 | public void testShortNameMatcher() { |
| 72 | assertThat(SHORT_NAME_MATCHER.apply("abc")).isFalse(); // no ~ in the name |
| 73 | assertThat(SHORT_NAME_MATCHER.apply("abc~")).isFalse(); // no number after the ~ |
| 74 | assertThat(SHORT_NAME_MATCHER.apply("~abc")).isFalse(); // no ~ followed by number |
| 75 | assertThat(SHORT_NAME_MATCHER.apply("too_long_path")).isFalse(); // too long for 8dot3 |
| 76 | assertThat(SHORT_NAME_MATCHER.apply("too_long_path~1")).isFalse(); // too long for 8dot3 |
| 77 | assertThat(SHORT_NAME_MATCHER.apply("abcd~1234")).isFalse(); // too long for 8dot3 |
| 78 | assertThat(SHORT_NAME_MATCHER.apply("h~1")).isTrue(); |
| 79 | assertThat(SHORT_NAME_MATCHER.apply("h~12")).isTrue(); |
| 80 | assertThat(SHORT_NAME_MATCHER.apply("h~12.")).isTrue(); |
| 81 | assertThat(SHORT_NAME_MATCHER.apply("h~12.a")).isTrue(); |
| 82 | assertThat(SHORT_NAME_MATCHER.apply("h~12.abc")).isTrue(); |
| 83 | assertThat(SHORT_NAME_MATCHER.apply("h~123456")).isTrue(); |
| 84 | assertThat(SHORT_NAME_MATCHER.apply("hellow~1")).isTrue(); |
| 85 | assertThat(SHORT_NAME_MATCHER.apply("hellow~1.")).isTrue(); |
| 86 | assertThat(SHORT_NAME_MATCHER.apply("hellow~1.a")).isTrue(); |
| 87 | assertThat(SHORT_NAME_MATCHER.apply("hellow~1.abc")).isTrue(); |
| 88 | assertThat(SHORT_NAME_MATCHER.apply("hello~1.abcd")).isFalse(); // too long for 8dot3 |
| 89 | assertThat(SHORT_NAME_MATCHER.apply("hellow~1.abcd")).isFalse(); // too long for 8dot3 |
| 90 | assertThat(SHORT_NAME_MATCHER.apply("hello~12")).isTrue(); |
| 91 | assertThat(SHORT_NAME_MATCHER.apply("hello~12.")).isTrue(); |
| 92 | assertThat(SHORT_NAME_MATCHER.apply("hello~12.a")).isTrue(); |
| 93 | assertThat(SHORT_NAME_MATCHER.apply("hello~12.abc")).isTrue(); |
| 94 | assertThat(SHORT_NAME_MATCHER.apply("hello~12.abcd")).isFalse(); // too long for 8dot3 |
| 95 | assertThat(SHORT_NAME_MATCHER.apply("hellow~12")).isFalse(); // too long for 8dot3 |
| 96 | assertThat(SHORT_NAME_MATCHER.apply("hellow~12.")).isFalse(); // too long for 8dot3 |
| 97 | assertThat(SHORT_NAME_MATCHER.apply("hellow~12.a")).isFalse(); // too long for 8dot3 |
| 98 | assertThat(SHORT_NAME_MATCHER.apply("hellow~12.ab")).isFalse(); // too long for 8dot3 |
| 99 | assertThat(SHORT_NAME_MATCHER.apply("~h~1")).isTrue(); |
| 100 | assertThat(SHORT_NAME_MATCHER.apply("~h~1.")).isTrue(); |
| 101 | assertThat(SHORT_NAME_MATCHER.apply("~h~1.a")).isTrue(); |
| 102 | assertThat(SHORT_NAME_MATCHER.apply("~h~1.abc")).isTrue(); |
| 103 | assertThat(SHORT_NAME_MATCHER.apply("~h~1.abcd")).isFalse(); // too long for 8dot3 |
| 104 | assertThat(SHORT_NAME_MATCHER.apply("~h~12")).isTrue(); |
| 105 | assertThat(SHORT_NAME_MATCHER.apply("~h~12~1")).isTrue(); |
| 106 | assertThat(SHORT_NAME_MATCHER.apply("~h~12~1.")).isTrue(); |
| 107 | assertThat(SHORT_NAME_MATCHER.apply("~h~12~1.a")).isTrue(); |
| 108 | assertThat(SHORT_NAME_MATCHER.apply("~h~12~1.abc")).isTrue(); |
| 109 | assertThat(SHORT_NAME_MATCHER.apply("~h~12~1.abcd")).isFalse(); // too long for 8dot3 |
| 110 | } |
| 111 | |
| 112 | @Test |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 113 | public void testCanWorkWithJunctionSymlinks() throws Exception { |
| 114 | testUtil.scratchFile("dir\\hello.txt", "hello"); |
| 115 | testUtil.scratchDir("non_existent"); |
| 116 | testUtil.createJunctions(ImmutableMap.of("junc", "dir", "junc_bad", "non_existent")); |
| 117 | |
| 118 | Path juncPath = testUtil.createVfsPath(fs, "junc"); |
| 119 | Path dirPath = testUtil.createVfsPath(fs, "dir"); |
| 120 | Path juncBadPath = testUtil.createVfsPath(fs, "junc_bad"); |
| 121 | Path nonExistentPath = testUtil.createVfsPath(fs, "non_existent"); |
| 122 | |
| 123 | // Test junction creation. |
Ulf Adams | 8afbd3c | 2017-02-28 10:42:48 +0000 | [diff] [blame] | 124 | assertThat(juncPath.exists(Symlinks.NOFOLLOW)).isTrue(); |
| 125 | assertThat(dirPath.exists(Symlinks.NOFOLLOW)).isTrue(); |
| 126 | assertThat(juncBadPath.exists(Symlinks.NOFOLLOW)).isTrue(); |
| 127 | assertThat(nonExistentPath.exists(Symlinks.NOFOLLOW)).isTrue(); |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 128 | |
| 129 | // Test recognizing and dereferencing a directory junction. |
Ulf Adams | 8afbd3c | 2017-02-28 10:42:48 +0000 | [diff] [blame] | 130 | assertThat(juncPath.isSymbolicLink()).isTrue(); |
| 131 | assertThat(juncPath.isDirectory(Symlinks.FOLLOW)).isTrue(); |
| 132 | assertThat(juncPath.isDirectory(Symlinks.NOFOLLOW)).isFalse(); |
| 133 | assertThat(juncPath.getDirectoryEntries()) |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 134 | .containsExactly(testUtil.createVfsPath(fs, "junc\\hello.txt")); |
| 135 | |
| 136 | // Test deleting a directory junction. |
Ulf Adams | 8afbd3c | 2017-02-28 10:42:48 +0000 | [diff] [blame] | 137 | assertThat(juncPath.delete()).isTrue(); |
| 138 | assertThat(juncPath.exists(Symlinks.NOFOLLOW)).isFalse(); |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 139 | |
| 140 | // Test recognizing a dangling directory junction. |
Ulf Adams | 8afbd3c | 2017-02-28 10:42:48 +0000 | [diff] [blame] | 141 | assertThat(nonExistentPath.delete()).isTrue(); |
| 142 | assertThat(nonExistentPath.exists(Symlinks.NOFOLLOW)).isFalse(); |
| 143 | assertThat(juncBadPath.exists(Symlinks.NOFOLLOW)).isTrue(); |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 144 | // TODO(bazel-team): fix https://github.com/bazelbuild/bazel/issues/1690 and uncomment the |
| 145 | // assertion below. |
| 146 | //assertThat(fs.isSymbolicLink(juncBadPath)).isTrue(); |
| 147 | assertThat(fs.isDirectory(juncBadPath, /* followSymlinks */ true)).isFalse(); |
| 148 | assertThat(fs.isDirectory(juncBadPath, /* followSymlinks */ false)).isFalse(); |
| 149 | |
| 150 | // Test deleting a dangling junction. |
Ulf Adams | 8afbd3c | 2017-02-28 10:42:48 +0000 | [diff] [blame] | 151 | assertThat(juncBadPath.delete()).isTrue(); |
| 152 | assertThat(juncBadPath.exists(Symlinks.NOFOLLOW)).isFalse(); |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 153 | } |
| 154 | |
| 155 | @Test |
| 156 | public void testMockJunctionCreation() throws Exception { |
| 157 | String root = testUtil.scratchDir("dir").getParent().toString(); |
| 158 | testUtil.scratchFile("dir/file.txt", "hello"); |
| 159 | testUtil.createJunctions(ImmutableMap.of("junc", "dir")); |
| 160 | String[] children = new File(root + "/junc").list(); |
| 161 | assertThat(children).isNotNull(); |
| 162 | assertThat(children).hasLength(1); |
| 163 | assertThat(Arrays.asList(children)).containsExactly("file.txt"); |
| 164 | } |
| 165 | |
| 166 | @Test |
| 167 | public void testIsJunction() throws Exception { |
| 168 | final Map<String, String> junctions = new HashMap<>(); |
| 169 | junctions.put("shrtpath/a", "shrttrgt"); |
| 170 | junctions.put("shrtpath/b", "longtargetpath"); |
| 171 | junctions.put("shrtpath/c", "longta~1"); |
| 172 | junctions.put("longlinkpath/a", "shrttrgt"); |
| 173 | junctions.put("longlinkpath/b", "longtargetpath"); |
| 174 | junctions.put("longlinkpath/c", "longta~1"); |
| 175 | junctions.put("abbrev~1/a", "shrttrgt"); |
| 176 | junctions.put("abbrev~1/b", "longtargetpath"); |
| 177 | junctions.put("abbrev~1/c", "longta~1"); |
| 178 | |
| 179 | String root = testUtil.scratchDir("shrtpath").getParent().toAbsolutePath().toString(); |
| 180 | testUtil.scratchDir("longlinkpath"); |
| 181 | testUtil.scratchDir("abbreviated"); |
| 182 | testUtil.scratchDir("control/a"); |
| 183 | testUtil.scratchDir("control/b"); |
| 184 | testUtil.scratchDir("control/c"); |
| 185 | |
| 186 | testUtil.scratchFile("shrttrgt/file1.txt", "hello"); |
| 187 | testUtil.scratchFile("longtargetpath/file2.txt", "hello"); |
| 188 | |
| 189 | testUtil.createJunctions(junctions); |
| 190 | |
Laszlo Csomor | 124c16c | 2016-11-04 14:22:46 +0000 | [diff] [blame] | 191 | assertThat(WindowsFileSystem.isJunction(new File(root, "shrtpath/a"))).isTrue(); |
| 192 | assertThat(WindowsFileSystem.isJunction(new File(root, "shrtpath/b"))).isTrue(); |
| 193 | assertThat(WindowsFileSystem.isJunction(new File(root, "shrtpath/c"))).isTrue(); |
| 194 | assertThat(WindowsFileSystem.isJunction(new File(root, "longlinkpath/a"))).isTrue(); |
| 195 | assertThat(WindowsFileSystem.isJunction(new File(root, "longlinkpath/b"))).isTrue(); |
| 196 | assertThat(WindowsFileSystem.isJunction(new File(root, "longlinkpath/c"))).isTrue(); |
| 197 | assertThat(WindowsFileSystem.isJunction(new File(root, "longli~1/a"))).isTrue(); |
| 198 | assertThat(WindowsFileSystem.isJunction(new File(root, "longli~1/b"))).isTrue(); |
| 199 | assertThat(WindowsFileSystem.isJunction(new File(root, "longli~1/c"))).isTrue(); |
| 200 | assertThat(WindowsFileSystem.isJunction(new File(root, "abbreviated/a"))).isTrue(); |
| 201 | assertThat(WindowsFileSystem.isJunction(new File(root, "abbreviated/b"))).isTrue(); |
| 202 | assertThat(WindowsFileSystem.isJunction(new File(root, "abbreviated/c"))).isTrue(); |
| 203 | assertThat(WindowsFileSystem.isJunction(new File(root, "abbrev~1/a"))).isTrue(); |
| 204 | assertThat(WindowsFileSystem.isJunction(new File(root, "abbrev~1/b"))).isTrue(); |
| 205 | assertThat(WindowsFileSystem.isJunction(new File(root, "abbrev~1/c"))).isTrue(); |
| 206 | assertThat(WindowsFileSystem.isJunction(new File(root, "control/a"))).isFalse(); |
| 207 | assertThat(WindowsFileSystem.isJunction(new File(root, "control/b"))).isFalse(); |
| 208 | assertThat(WindowsFileSystem.isJunction(new File(root, "control/c"))).isFalse(); |
| 209 | assertThat(WindowsFileSystem.isJunction(new File(root, "shrttrgt/file1.txt"))) |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 210 | .isFalse(); |
Laszlo Csomor | 124c16c | 2016-11-04 14:22:46 +0000 | [diff] [blame] | 211 | assertThat(WindowsFileSystem.isJunction(new File(root, "longtargetpath/file2.txt"))) |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 212 | .isFalse(); |
Laszlo Csomor | 124c16c | 2016-11-04 14:22:46 +0000 | [diff] [blame] | 213 | assertThat(WindowsFileSystem.isJunction(new File(root, "longta~1/file2.txt"))) |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 214 | .isFalse(); |
Laszlo Csomor | fe7e57e | 2016-12-21 16:02:51 +0000 | [diff] [blame] | 215 | try { |
| 216 | WindowsFileSystem.isJunction(new File(root, "non-existent")); |
lberki | 4a45ea8 | 2017-06-01 10:05:42 +0200 | [diff] [blame] | 217 | fail("expected failure"); |
Laszlo Csomor | fe7e57e | 2016-12-21 16:02:51 +0000 | [diff] [blame] | 218 | } catch (IOException e) { |
| 219 | assertThat(e.getMessage()).contains("cannot find"); |
| 220 | } |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 221 | |
| 222 | assertThat(Arrays.asList(new File(root + "/shrtpath/a").list())).containsExactly("file1.txt"); |
| 223 | assertThat(Arrays.asList(new File(root + "/shrtpath/b").list())).containsExactly("file2.txt"); |
| 224 | assertThat(Arrays.asList(new File(root + "/shrtpath/c").list())).containsExactly("file2.txt"); |
| 225 | assertThat(Arrays.asList(new File(root + "/longlinkpath/a").list())) |
| 226 | .containsExactly("file1.txt"); |
| 227 | assertThat(Arrays.asList(new File(root + "/longlinkpath/b").list())) |
| 228 | .containsExactly("file2.txt"); |
| 229 | assertThat(Arrays.asList(new File(root + "/longlinkpath/c").list())) |
| 230 | .containsExactly("file2.txt"); |
| 231 | assertThat(Arrays.asList(new File(root + "/abbreviated/a").list())) |
| 232 | .containsExactly("file1.txt"); |
| 233 | assertThat(Arrays.asList(new File(root + "/abbreviated/b").list())) |
| 234 | .containsExactly("file2.txt"); |
| 235 | assertThat(Arrays.asList(new File(root + "/abbreviated/c").list())) |
| 236 | .containsExactly("file2.txt"); |
| 237 | } |
| 238 | |
| 239 | @Test |
| 240 | public void testIsJunctionIsTrueForDanglingJunction() throws Exception { |
| 241 | java.nio.file.Path helloPath = testUtil.scratchFile("target\\hello.txt", "hello"); |
| 242 | testUtil.createJunctions(ImmutableMap.of("link", "target")); |
| 243 | |
| 244 | File linkPath = new File(helloPath.getParent().getParent().toFile(), "link"); |
| 245 | assertThat(Arrays.asList(linkPath.list())).containsExactly("hello.txt"); |
Laszlo Csomor | 124c16c | 2016-11-04 14:22:46 +0000 | [diff] [blame] | 246 | assertThat(WindowsFileSystem.isJunction(linkPath)).isTrue(); |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 247 | |
| 248 | assertThat(helloPath.toFile().delete()).isTrue(); |
| 249 | assertThat(helloPath.getParent().toFile().delete()).isTrue(); |
| 250 | assertThat(helloPath.getParent().toFile().exists()).isFalse(); |
| 251 | assertThat(Arrays.asList(linkPath.getParentFile().list())).containsExactly("link"); |
| 252 | |
Laszlo Csomor | 124c16c | 2016-11-04 14:22:46 +0000 | [diff] [blame] | 253 | assertThat(WindowsFileSystem.isJunction(linkPath)).isTrue(); |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 254 | assertThat( |
| 255 | Files.exists( |
| 256 | linkPath.toPath(), WindowsFileSystem.symlinkOpts(/* followSymlinks */ false))) |
| 257 | .isTrue(); |
| 258 | assertThat( |
| 259 | Files.exists( |
| 260 | linkPath.toPath(), WindowsFileSystem.symlinkOpts(/* followSymlinks */ true))) |
| 261 | .isFalse(); |
| 262 | } |
Laszlo Csomor | aa1614b | 2016-12-15 11:16:44 +0000 | [diff] [blame] | 263 | |
| 264 | @Test |
| 265 | public void testIsJunctionHandlesFilesystemChangesCorrectly() throws Exception { |
| 266 | File longPath = |
| 267 | testUtil.scratchFile("target\\helloworld.txt", "hello").toAbsolutePath().toFile(); |
| 268 | File shortPath = new File(longPath.getParentFile(), "hellow~1.txt"); |
| 269 | assertThat(WindowsFileSystem.isJunction(longPath)).isFalse(); |
| 270 | assertThat(WindowsFileSystem.isJunction(shortPath)).isFalse(); |
| 271 | |
| 272 | assertThat(longPath.delete()).isTrue(); |
| 273 | testUtil.createJunctions(ImmutableMap.of("target\\helloworld.txt", "target")); |
| 274 | assertThat(WindowsFileSystem.isJunction(longPath)).isTrue(); |
| 275 | assertThat(WindowsFileSystem.isJunction(shortPath)).isTrue(); |
| 276 | |
| 277 | assertThat(longPath.delete()).isTrue(); |
| 278 | assertThat(longPath.mkdir()).isTrue(); |
| 279 | assertThat(WindowsFileSystem.isJunction(longPath)).isFalse(); |
| 280 | assertThat(WindowsFileSystem.isJunction(shortPath)).isFalse(); |
| 281 | } |
Laszlo Csomor | 8679e4c | 2017-01-03 15:21:08 +0000 | [diff] [blame] | 282 | |
| 283 | @Test |
| 284 | public void testShortPathResolution() throws Exception { |
| 285 | String shortPath = "shortp~1.res/foo/withsp~1/bar/~witht~1/hello.txt"; |
| 286 | String longPath = "shortpath.resolution/foo/with spaces/bar/~with tilde/hello.txt"; |
| 287 | testUtil.scratchFile(longPath, "hello"); |
| 288 | Path p = fs.getPath(scratchRoot).getRelative(shortPath); |
| 289 | assertThat(p.getPathString()).endsWith(longPath); |
| 290 | assertThat(p).isEqualTo(fs.getPath(scratchRoot).getRelative(shortPath)); |
| 291 | assertThat(p).isEqualTo(fs.getPath(scratchRoot).getRelative(longPath)); |
lberki | e355e77 | 2017-05-31 14:34:53 +0200 | [diff] [blame] | 292 | assertThat(fs.getPath(scratchRoot).getRelative(shortPath)).isSameAs(p); |
| 293 | assertThat(fs.getPath(scratchRoot).getRelative(longPath)).isSameAs(p); |
Laszlo Csomor | 8679e4c | 2017-01-03 15:21:08 +0000 | [diff] [blame] | 294 | } |
| 295 | |
| 296 | @Test |
| 297 | public void testUnresolvableShortPathWhichIsThenCreated() throws Exception { |
| 298 | String shortPath = "unreso~1.sho/foo/will~1.exi/bar/hello.txt"; |
| 299 | String longPrefix = "unresolvable.shortpath/foo/"; |
| 300 | String longPath = longPrefix + "will.exist/bar/hello.txt"; |
| 301 | testUtil.scratchDir(longPrefix); |
Ulf Adams | 8afbd3c | 2017-02-28 10:42:48 +0000 | [diff] [blame] | 302 | final WindowsPath foo = (WindowsPath) fs.getPath(scratchRoot).getRelative(longPrefix); |
Laszlo Csomor | 8679e4c | 2017-01-03 15:21:08 +0000 | [diff] [blame] | 303 | |
| 304 | // Assert that we can create an unresolvable path. |
| 305 | Path p = fs.getPath(scratchRoot).getRelative(shortPath); |
| 306 | assertThat(p.getPathString()).endsWith(longPrefix + "will~1.exi/bar/hello.txt"); |
| 307 | // Assert that said path is not cached in its parent's `children` cache. |
| 308 | final List<String> children = new ArrayList<>(); |
| 309 | Predicate<Path> collector = |
| 310 | new Predicate<Path>() { |
| 311 | @Override |
| 312 | public boolean apply(Path child) { |
| 313 | children.add(child.relativeTo(foo).getPathString()); |
| 314 | return true; |
| 315 | } |
| 316 | }; |
| 317 | foo.applyToChildren(collector); |
| 318 | assertThat(children).isEmpty(); |
| 319 | // Assert that we can then create the whole path, and can now resolve the short form. |
| 320 | testUtil.scratchFile(longPath, "hello"); |
| 321 | Path q = fs.getPath(scratchRoot).getRelative(shortPath); |
| 322 | assertThat(q.getPathString()).endsWith(longPath); |
| 323 | // Assert however that the unresolved and resolved Path objects are different, and only the |
| 324 | // resolved one is cached. |
| 325 | assertThat(p).isNotEqualTo(q); |
| 326 | foo.applyToChildren(collector); |
| 327 | assertThat(children).containsExactly("will.exist"); |
| 328 | } |
| 329 | |
| 330 | /** |
| 331 | * Test the scenario when a short path resolves to different long ones over time. |
| 332 | * |
| 333 | * <p>This can happen if the user deletes a directory during the bazel server's lifetime, then |
| 334 | * recreates it with the same name prefix such that the resulting directory's 8dot3 name is the |
| 335 | * same as the old one's. |
| 336 | */ |
| 337 | @Test |
| 338 | public void testShortPathResolvesToDifferentPathsOverTime() throws Exception { |
| 339 | Path p1 = fs.getPath(scratchRoot).getRelative("longpa~1"); |
| 340 | Path p2 = fs.getPath(scratchRoot).getRelative("longpa~1"); |
| 341 | assertThat(p1.exists()).isFalse(); |
| 342 | assertThat(p1).isEqualTo(p2); |
| 343 | assertThat(p1).isNotSameAs(p2); |
| 344 | |
| 345 | testUtil.scratchDir("longpathnow"); |
| 346 | Path q1 = fs.getPath(scratchRoot).getRelative("longpa~1"); |
| 347 | Path q2 = fs.getPath(scratchRoot).getRelative("longpa~1"); |
| 348 | assertThat(q1.exists()).isTrue(); |
| 349 | assertThat(q1).isEqualTo(q2); |
| 350 | // Assert q1 == q2, because we could successfully resolve the short path to a long name and we |
| 351 | // cache them by the long name, so it's irrelevant they were created from a 8dot3 name, or what |
| 352 | // that name resolves to later in time. |
| 353 | assertThat(q1).isSameAs(q2); |
| 354 | assertThat(q1).isSameAs(fs.getPath(scratchRoot).getRelative("longpathnow")); |
| 355 | |
| 356 | // Delete the original resolution of "longpa~1" ("longpathnow"). |
| 357 | assertThat(q1.delete()).isTrue(); |
| 358 | assertThat(q1.exists()).isFalse(); |
| 359 | |
| 360 | // Create a directory whose 8dot3 name is also "longpa~1" but its long name is different. |
| 361 | testUtil.scratchDir("longpaththen"); |
| 362 | Path r1 = fs.getPath(scratchRoot).getRelative("longpa~1"); |
| 363 | Path r2 = fs.getPath(scratchRoot).getRelative("longpa~1"); |
| 364 | assertThat(r1.exists()).isTrue(); |
| 365 | assertThat(r1).isEqualTo(r2); |
| 366 | assertThat(r1).isSameAs(r2); |
| 367 | assertThat(r1).isSameAs(fs.getPath(scratchRoot).getRelative("longpaththen")); |
| 368 | // r1 == r2 and q1 == q2, but r1 != q1, because the resolution of "longpa~1" changed over time. |
| 369 | assertThat(r1).isNotEqualTo(q1); |
| 370 | assertThat(r1).isNotSameAs(q1); |
| 371 | } |
Laszlo Csomor | 81f92fe | 2017-02-15 16:08:45 +0000 | [diff] [blame] | 372 | |
| 373 | @Test |
| 374 | public void testCreateSymbolicLink() throws Exception { |
| 375 | // Create the `scratchRoot` directory. |
| 376 | assertThat(fs.getPath(scratchRoot).createDirectory()).isTrue(); |
| 377 | // Create symlink with directory target, relative path. |
| 378 | Path link1 = fs.getPath(scratchRoot).getRelative("link1"); |
nharmata | 4d2a0a1 | 2017-04-06 17:56:18 +0000 | [diff] [blame] | 379 | fs.createSymbolicLink(link1, PathFragment.create("..")); |
Laszlo Csomor | 81f92fe | 2017-02-15 16:08:45 +0000 | [diff] [blame] | 380 | // Create symlink with directory target, absolute path. |
| 381 | Path link2 = fs.getPath(scratchRoot).getRelative("link2"); |
| 382 | fs.createSymbolicLink(link2, fs.getPath(scratchRoot).getRelative("link1").asFragment()); |
| 383 | // Create scratch files that'll be symlink targets. |
| 384 | testUtil.scratchFile("foo.txt", "hello"); |
| 385 | testUtil.scratchFile("bar.txt", "hello"); |
| 386 | // Create symlink with file target, relative path. |
| 387 | Path link3 = fs.getPath(scratchRoot).getRelative("link3"); |
nharmata | 4d2a0a1 | 2017-04-06 17:56:18 +0000 | [diff] [blame] | 388 | fs.createSymbolicLink(link3, PathFragment.create("foo.txt")); |
Laszlo Csomor | 81f92fe | 2017-02-15 16:08:45 +0000 | [diff] [blame] | 389 | // Create symlink with file target, absolute path. |
| 390 | Path link4 = fs.getPath(scratchRoot).getRelative("link4"); |
| 391 | fs.createSymbolicLink(link4, fs.getPath(scratchRoot).getRelative("bar.txt").asFragment()); |
| 392 | // Assert that link1 and link2 are true junctions and have the right contents. |
| 393 | for (Path p : ImmutableList.of(link1, link2)) { |
| 394 | assertThat(WindowsFileOperations.isJunction(p.getPathString())).isTrue(); |
| 395 | assertThat(p.isSymbolicLink()).isTrue(); |
| 396 | assertThat( |
| 397 | Iterables.transform( |
| 398 | Arrays.asList(new File(p.getPathString()).listFiles()), |
| 399 | new Function<File, String>() { |
| 400 | @Override |
| 401 | public String apply(File input) { |
| 402 | return input.getName(); |
| 403 | } |
| 404 | })) |
| 405 | .containsExactly("x"); |
| 406 | } |
| 407 | // Assert that link3 and link4 are copies of files. |
| 408 | for (Path p : ImmutableList.of(link3, link4)) { |
| 409 | assertThat(WindowsFileOperations.isJunction(p.getPathString())).isFalse(); |
| 410 | assertThat(p.isSymbolicLink()).isFalse(); |
| 411 | assertThat(p.isFile()).isTrue(); |
| 412 | } |
| 413 | } |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 414 | } |