Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +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 | |
| 15 | package com.google.devtools.build.lib.windows; |
| 16 | |
| 17 | import static com.google.common.truth.Truth.assertThat; |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 18 | import static org.junit.Assert.fail; |
| 19 | |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 20 | import com.google.common.collect.ImmutableMap; |
| 21 | import com.google.devtools.build.lib.testutil.TestSpec; |
| 22 | import com.google.devtools.build.lib.util.OS; |
Laszlo Csomor | 13f9226 | 2017-06-30 16:22:41 +0200 | [diff] [blame] | 23 | import com.google.devtools.build.lib.windows.jni.WindowsFileOperations; |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 24 | import com.google.devtools.build.lib.windows.util.WindowsTestUtil; |
| 25 | import java.io.File; |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 26 | import java.io.IOException; |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 27 | import java.nio.file.Files; |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 28 | import java.util.Arrays; |
| 29 | import java.util.HashMap; |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 30 | import java.util.Map; |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 31 | import org.junit.After; |
| 32 | import org.junit.Before; |
| 33 | import org.junit.Test; |
| 34 | import org.junit.runner.RunWith; |
| 35 | import org.junit.runners.JUnit4; |
| 36 | |
| 37 | /** Unit tests for {@link WindowsFileOperations}. */ |
| 38 | @RunWith(JUnit4.class) |
| 39 | @TestSpec(localOnly = true, supportedOs = OS.WINDOWS) |
| 40 | public class WindowsFileOperationsTest { |
| 41 | |
| 42 | private String scratchRoot; |
Laszlo Csomor | b65d754 | 2016-09-07 10:22:06 +0000 | [diff] [blame] | 43 | private WindowsTestUtil testUtil; |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 44 | |
| 45 | @Before |
| 46 | public void loadJni() throws Exception { |
Yun Peng | 6a4247b | 2017-10-24 14:36:10 +0200 | [diff] [blame] | 47 | scratchRoot = new File(System.getenv("TEST_TMPDIR"), "x").getAbsolutePath(); |
Laszlo Csomor | b65d754 | 2016-09-07 10:22:06 +0000 | [diff] [blame] | 48 | testUtil = new WindowsTestUtil(scratchRoot); |
Laszlo Csomor | a2da311 | 2016-09-07 08:06:15 +0000 | [diff] [blame] | 49 | cleanupScratchDir(); |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 50 | } |
| 51 | |
| 52 | @After |
| 53 | public void cleanupScratchDir() throws Exception { |
Laszlo Csomor | b65d754 | 2016-09-07 10:22:06 +0000 | [diff] [blame] | 54 | testUtil.deleteAllUnder(""); |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 55 | } |
| 56 | |
| 57 | @Test |
| 58 | public void testMockJunctionCreation() throws Exception { |
Laszlo Csomor | b65d754 | 2016-09-07 10:22:06 +0000 | [diff] [blame] | 59 | String root = testUtil.scratchDir("dir").getParent().toString(); |
| 60 | testUtil.scratchFile("dir/file.txt", "hello"); |
| 61 | testUtil.createJunctions(ImmutableMap.of("junc", "dir")); |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 62 | String[] children = new File(root + "/junc").list(); |
| 63 | assertThat(children).isNotNull(); |
| 64 | assertThat(children).hasLength(1); |
| 65 | assertThat(Arrays.asList(children)).containsExactly("file.txt"); |
| 66 | } |
| 67 | |
| 68 | @Test |
| 69 | public void testIsJunction() throws Exception { |
| 70 | final Map<String, String> junctions = new HashMap<>(); |
| 71 | junctions.put("shrtpath/a", "shrttrgt"); |
| 72 | junctions.put("shrtpath/b", "longtargetpath"); |
| 73 | junctions.put("shrtpath/c", "longta~1"); |
| 74 | junctions.put("longlinkpath/a", "shrttrgt"); |
| 75 | junctions.put("longlinkpath/b", "longtargetpath"); |
| 76 | junctions.put("longlinkpath/c", "longta~1"); |
| 77 | junctions.put("abbrev~1/a", "shrttrgt"); |
| 78 | junctions.put("abbrev~1/b", "longtargetpath"); |
| 79 | junctions.put("abbrev~1/c", "longta~1"); |
| 80 | |
Laszlo Csomor | b65d754 | 2016-09-07 10:22:06 +0000 | [diff] [blame] | 81 | String root = testUtil.scratchDir("shrtpath").getParent().toAbsolutePath().toString(); |
| 82 | testUtil.scratchDir("longlinkpath"); |
| 83 | testUtil.scratchDir("abbreviated"); |
| 84 | testUtil.scratchDir("control/a"); |
| 85 | testUtil.scratchDir("control/b"); |
| 86 | testUtil.scratchDir("control/c"); |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 87 | |
Laszlo Csomor | b65d754 | 2016-09-07 10:22:06 +0000 | [diff] [blame] | 88 | testUtil.scratchFile("shrttrgt/file1.txt", "hello"); |
| 89 | testUtil.scratchFile("longtargetpath/file2.txt", "hello"); |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 90 | |
Laszlo Csomor | b65d754 | 2016-09-07 10:22:06 +0000 | [diff] [blame] | 91 | testUtil.createJunctions(junctions); |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 92 | |
Laszlo Csomor | c60be00 | 2019-04-04 07:36:05 -0700 | [diff] [blame] | 93 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\shrtpath\\a")).isTrue(); |
| 94 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\shrtpath\\b")).isTrue(); |
| 95 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\shrtpath\\c")).isTrue(); |
| 96 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\longlinkpath\\a")).isTrue(); |
| 97 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\longlinkpath\\b")).isTrue(); |
| 98 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\longlinkpath\\c")).isTrue(); |
| 99 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\longli~1\\a")).isTrue(); |
| 100 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\longli~1\\b")).isTrue(); |
| 101 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\longli~1\\c")).isTrue(); |
| 102 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\abbreviated\\a")).isTrue(); |
| 103 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\abbreviated\\b")).isTrue(); |
| 104 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\abbreviated\\c")).isTrue(); |
| 105 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\abbrev~1\\a")).isTrue(); |
| 106 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\abbrev~1\\b")).isTrue(); |
| 107 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\abbrev~1\\c")).isTrue(); |
| 108 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\control\\a")).isFalse(); |
| 109 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\control\\b")).isFalse(); |
| 110 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\control\\c")).isFalse(); |
| 111 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\shrttrgt\\file1.txt")).isFalse(); |
| 112 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\longtargetpath\\file2.txt")) |
| 113 | .isFalse(); |
| 114 | assertThat(WindowsFileOperations.isSymlinkOrJunction(root + "\\longta~1\\file2.txt")).isFalse(); |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 115 | try { |
Laszlo Csomor | c60be00 | 2019-04-04 07:36:05 -0700 | [diff] [blame] | 116 | WindowsFileOperations.isSymlinkOrJunction(root + "\\non-existent"); |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 117 | fail("expected to throw"); |
| 118 | } catch (IOException e) { |
Laszlo Csomor | c60be00 | 2019-04-04 07:36:05 -0700 | [diff] [blame] | 119 | assertThat(e.getMessage()).contains("path does not exist"); |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 120 | } |
| 121 | assertThat(Arrays.asList(new File(root + "/shrtpath/a").list())).containsExactly("file1.txt"); |
| 122 | assertThat(Arrays.asList(new File(root + "/shrtpath/b").list())).containsExactly("file2.txt"); |
| 123 | assertThat(Arrays.asList(new File(root + "/shrtpath/c").list())).containsExactly("file2.txt"); |
| 124 | assertThat(Arrays.asList(new File(root + "/longlinkpath/a").list())) |
| 125 | .containsExactly("file1.txt"); |
| 126 | assertThat(Arrays.asList(new File(root + "/longlinkpath/b").list())) |
| 127 | .containsExactly("file2.txt"); |
| 128 | assertThat(Arrays.asList(new File(root + "/longlinkpath/c").list())) |
| 129 | .containsExactly("file2.txt"); |
| 130 | assertThat(Arrays.asList(new File(root + "/abbreviated/a").list())) |
| 131 | .containsExactly("file1.txt"); |
| 132 | assertThat(Arrays.asList(new File(root + "/abbreviated/b").list())) |
| 133 | .containsExactly("file2.txt"); |
| 134 | assertThat(Arrays.asList(new File(root + "/abbreviated/c").list())) |
| 135 | .containsExactly("file2.txt"); |
| 136 | } |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 137 | |
| 138 | @Test |
| 139 | public void testIsJunctionIsTrueForDanglingJunction() throws Exception { |
| 140 | java.nio.file.Path helloPath = testUtil.scratchFile("target\\hello.txt", "hello"); |
| 141 | testUtil.createJunctions(ImmutableMap.of("link", "target")); |
| 142 | |
| 143 | File linkPath = new File(helloPath.getParent().getParent().toFile(), "link"); |
| 144 | assertThat(Arrays.asList(linkPath.list())).containsExactly("hello.txt"); |
Laszlo Csomor | c60be00 | 2019-04-04 07:36:05 -0700 | [diff] [blame] | 145 | assertThat(WindowsFileOperations.isSymlinkOrJunction(linkPath.getAbsolutePath())).isTrue(); |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 146 | |
| 147 | assertThat(helloPath.toFile().delete()).isTrue(); |
| 148 | assertThat(helloPath.getParent().toFile().delete()).isTrue(); |
| 149 | assertThat(helloPath.getParent().toFile().exists()).isFalse(); |
| 150 | assertThat(Arrays.asList(linkPath.getParentFile().list())).containsExactly("link"); |
| 151 | |
Laszlo Csomor | c60be00 | 2019-04-04 07:36:05 -0700 | [diff] [blame] | 152 | assertThat(WindowsFileOperations.isSymlinkOrJunction(linkPath.getAbsolutePath())).isTrue(); |
Laszlo Csomor | 94d9058 | 2016-09-08 15:08:00 +0000 | [diff] [blame] | 153 | assertThat( |
| 154 | Files.exists( |
| 155 | linkPath.toPath(), WindowsFileSystem.symlinkOpts(/* followSymlinks */ false))) |
| 156 | .isTrue(); |
| 157 | assertThat( |
| 158 | Files.exists( |
| 159 | linkPath.toPath(), WindowsFileSystem.symlinkOpts(/* followSymlinks */ true))) |
| 160 | .isFalse(); |
| 161 | } |
Laszlo Csomor | aa1614b | 2016-12-15 11:16:44 +0000 | [diff] [blame] | 162 | |
| 163 | @Test |
| 164 | public void testIsJunctionHandlesFilesystemChangesCorrectly() throws Exception { |
| 165 | File helloFile = |
| 166 | testUtil.scratchFile("target\\helloworld.txt", "hello").toAbsolutePath().toFile(); |
| 167 | |
| 168 | // Assert that a file is identified as not a junction. |
| 169 | String longPath = helloFile.getAbsolutePath(); |
| 170 | String shortPath = new File(helloFile.getParentFile(), "hellow~1.txt").getAbsolutePath(); |
Laszlo Csomor | c60be00 | 2019-04-04 07:36:05 -0700 | [diff] [blame] | 171 | assertThat(WindowsFileOperations.isSymlinkOrJunction(longPath)).isFalse(); |
| 172 | assertThat(WindowsFileOperations.isSymlinkOrJunction(shortPath)).isFalse(); |
Laszlo Csomor | aa1614b | 2016-12-15 11:16:44 +0000 | [diff] [blame] | 173 | |
| 174 | // Assert that after deleting the file and creating a junction with the same path, it is |
| 175 | // identified as a junction. |
| 176 | assertThat(helloFile.delete()).isTrue(); |
| 177 | testUtil.createJunctions(ImmutableMap.of("target\\helloworld.txt", "target")); |
Laszlo Csomor | c60be00 | 2019-04-04 07:36:05 -0700 | [diff] [blame] | 178 | assertThat(WindowsFileOperations.isSymlinkOrJunction(longPath)).isTrue(); |
| 179 | assertThat(WindowsFileOperations.isSymlinkOrJunction(shortPath)).isTrue(); |
Laszlo Csomor | aa1614b | 2016-12-15 11:16:44 +0000 | [diff] [blame] | 180 | |
| 181 | // Assert that after deleting the file and creating a directory with the same path, it is |
| 182 | // identified as not a junction. |
| 183 | assertThat(helloFile.delete()).isTrue(); |
| 184 | assertThat(helloFile.mkdir()).isTrue(); |
Laszlo Csomor | c60be00 | 2019-04-04 07:36:05 -0700 | [diff] [blame] | 185 | assertThat(WindowsFileOperations.isSymlinkOrJunction(longPath)).isFalse(); |
| 186 | assertThat(WindowsFileOperations.isSymlinkOrJunction(shortPath)).isFalse(); |
Laszlo Csomor | aa1614b | 2016-12-15 11:16:44 +0000 | [diff] [blame] | 187 | } |
| 188 | |
| 189 | @Test |
| 190 | public void testGetLongPath() throws Exception { |
| 191 | File foo = testUtil.scratchDir("foo").toAbsolutePath().toFile(); |
| 192 | assertThat(foo.exists()).isTrue(); |
| 193 | assertThat(WindowsFileOperations.getLongPath(foo.getAbsolutePath())).endsWith("foo"); |
| 194 | |
| 195 | String longPath = foo.getAbsolutePath() + "\\will.exist\\helloworld.txt"; |
| 196 | String shortPath = foo.getAbsolutePath() + "\\will~1.exi\\hellow~1.txt"; |
| 197 | |
| 198 | // Assert that the long path resolution fails for non-existent file. |
| 199 | try { |
| 200 | WindowsFileOperations.getLongPath(longPath); |
| 201 | fail("expected to throw"); |
| 202 | } catch (IOException e) { |
| 203 | assertThat(e.getMessage()).contains("GetLongPathName"); |
| 204 | } |
| 205 | try { |
| 206 | WindowsFileOperations.getLongPath(shortPath); |
| 207 | fail("expected to throw"); |
| 208 | } catch (IOException e) { |
| 209 | assertThat(e.getMessage()).contains("GetLongPathName"); |
| 210 | } |
| 211 | |
| 212 | // Create the file, assert that long path resolution works and is correct. |
| 213 | File helloFile = |
| 214 | testUtil.scratchFile("foo/will.exist/helloworld.txt", "hello").toAbsolutePath().toFile(); |
| 215 | assertThat(helloFile.getAbsolutePath()).isEqualTo(longPath); |
| 216 | assertThat(helloFile.exists()).isTrue(); |
| 217 | assertThat(new File(longPath).exists()).isTrue(); |
| 218 | assertThat(new File(shortPath).exists()).isTrue(); |
Laszlo Csomor | 84aaca1 | 2019-01-24 05:33:21 -0800 | [diff] [blame] | 219 | assertThat(WindowsFileOperations.getLongPath(longPath)).endsWith("will.exist/helloworld.txt"); |
| 220 | assertThat(WindowsFileOperations.getLongPath(shortPath)).endsWith("will.exist/helloworld.txt"); |
Laszlo Csomor | aa1614b | 2016-12-15 11:16:44 +0000 | [diff] [blame] | 221 | |
| 222 | // Delete the file and the directory, assert that long path resolution fails for them. |
| 223 | assertThat(helloFile.delete()).isTrue(); |
| 224 | assertThat(helloFile.getParentFile().delete()).isTrue(); |
| 225 | try { |
| 226 | WindowsFileOperations.getLongPath(longPath); |
| 227 | fail("expected to throw"); |
| 228 | } catch (IOException e) { |
| 229 | assertThat(e.getMessage()).contains("GetLongPathName"); |
| 230 | } |
| 231 | try { |
| 232 | WindowsFileOperations.getLongPath(shortPath); |
| 233 | fail("expected to throw"); |
| 234 | } catch (IOException e) { |
| 235 | assertThat(e.getMessage()).contains("GetLongPathName"); |
| 236 | } |
| 237 | |
| 238 | // Create the directory and file with different names, but same 8dot3 names, assert that the |
| 239 | // resolution is still correct. |
| 240 | helloFile = |
| 241 | testUtil |
| 242 | .scratchFile("foo/will.exist_again/hellowelt.txt", "hello") |
| 243 | .toAbsolutePath() |
| 244 | .toFile(); |
| 245 | assertThat(new File(shortPath).exists()).isTrue(); |
| 246 | assertThat(WindowsFileOperations.getLongPath(shortPath)) |
Laszlo Csomor | 84aaca1 | 2019-01-24 05:33:21 -0800 | [diff] [blame] | 247 | .endsWith("will.exist_again/hellowelt.txt"); |
Laszlo Csomor | aa1614b | 2016-12-15 11:16:44 +0000 | [diff] [blame] | 248 | assertThat(WindowsFileOperations.getLongPath(foo + "\\will.exist_again\\hellowelt.txt")) |
Laszlo Csomor | 84aaca1 | 2019-01-24 05:33:21 -0800 | [diff] [blame] | 249 | .endsWith("will.exist_again/hellowelt.txt"); |
Laszlo Csomor | aa1614b | 2016-12-15 11:16:44 +0000 | [diff] [blame] | 250 | try { |
| 251 | WindowsFileOperations.getLongPath(longPath); |
| 252 | fail("expected to throw"); |
| 253 | } catch (IOException e) { |
| 254 | assertThat(e.getMessage()).contains("GetLongPathName"); |
| 255 | } |
| 256 | } |
Laszlo Csomor | 4fca988 | 2016-09-02 09:48:42 +0000 | [diff] [blame] | 257 | } |