blob: 9c04f8bd3e9a9e45ae4a9f349d2de21fb018ff6d [file] [log] [blame]
Laszlo Csomor4fca9882016-09-02 09:48:42 +00001// 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
15package com.google.devtools.build.lib.windows;
16
17import static com.google.common.truth.Truth.assertThat;
Laszlo Csomor4fca9882016-09-02 09:48:42 +000018import static org.junit.Assert.fail;
19
Laszlo Csomor4fca9882016-09-02 09:48:42 +000020import com.google.common.collect.ImmutableMap;
21import com.google.devtools.build.lib.testutil.TestSpec;
22import com.google.devtools.build.lib.util.OS;
Laszlo Csomor13f92262017-06-30 16:22:41 +020023import com.google.devtools.build.lib.windows.jni.WindowsFileOperations;
Laszlo Csomor4fca9882016-09-02 09:48:42 +000024import com.google.devtools.build.lib.windows.util.WindowsTestUtil;
25import java.io.File;
Laszlo Csomor4fca9882016-09-02 09:48:42 +000026import java.io.IOException;
Laszlo Csomor94d90582016-09-08 15:08:00 +000027import java.nio.file.Files;
Laszlo Csomor4fca9882016-09-02 09:48:42 +000028import java.util.Arrays;
29import java.util.HashMap;
Laszlo Csomor4fca9882016-09-02 09:48:42 +000030import java.util.Map;
Laszlo Csomor4fca9882016-09-02 09:48:42 +000031import org.junit.After;
32import org.junit.Before;
33import org.junit.Test;
34import org.junit.runner.RunWith;
35import org.junit.runners.JUnit4;
36
37/** Unit tests for {@link WindowsFileOperations}. */
38@RunWith(JUnit4.class)
39@TestSpec(localOnly = true, supportedOs = OS.WINDOWS)
40public class WindowsFileOperationsTest {
41
42 private String scratchRoot;
Laszlo Csomorb65d7542016-09-07 10:22:06 +000043 private WindowsTestUtil testUtil;
Laszlo Csomor4fca9882016-09-02 09:48:42 +000044
45 @Before
46 public void loadJni() throws Exception {
Yun Peng6a4247b2017-10-24 14:36:10 +020047 scratchRoot = new File(System.getenv("TEST_TMPDIR"), "x").getAbsolutePath();
Laszlo Csomorb65d7542016-09-07 10:22:06 +000048 testUtil = new WindowsTestUtil(scratchRoot);
Laszlo Csomora2da3112016-09-07 08:06:15 +000049 cleanupScratchDir();
Laszlo Csomor4fca9882016-09-02 09:48:42 +000050 }
51
52 @After
53 public void cleanupScratchDir() throws Exception {
Laszlo Csomorb65d7542016-09-07 10:22:06 +000054 testUtil.deleteAllUnder("");
Laszlo Csomor4fca9882016-09-02 09:48:42 +000055 }
56
57 @Test
58 public void testMockJunctionCreation() throws Exception {
Laszlo Csomorb65d7542016-09-07 10:22:06 +000059 String root = testUtil.scratchDir("dir").getParent().toString();
60 testUtil.scratchFile("dir/file.txt", "hello");
61 testUtil.createJunctions(ImmutableMap.of("junc", "dir"));
Laszlo Csomor4fca9882016-09-02 09:48:42 +000062 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 Csomorb65d7542016-09-07 10:22:06 +000081 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 Csomor4fca9882016-09-02 09:48:42 +000087
Laszlo Csomorb65d7542016-09-07 10:22:06 +000088 testUtil.scratchFile("shrttrgt/file1.txt", "hello");
89 testUtil.scratchFile("longtargetpath/file2.txt", "hello");
Laszlo Csomor4fca9882016-09-02 09:48:42 +000090
Laszlo Csomorb65d7542016-09-07 10:22:06 +000091 testUtil.createJunctions(junctions);
Laszlo Csomor4fca9882016-09-02 09:48:42 +000092
Laszlo Csomorc60be002019-04-04 07:36:05 -070093 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 Csomor4fca9882016-09-02 09:48:42 +0000115 try {
Laszlo Csomorc60be002019-04-04 07:36:05 -0700116 WindowsFileOperations.isSymlinkOrJunction(root + "\\non-existent");
Laszlo Csomor4fca9882016-09-02 09:48:42 +0000117 fail("expected to throw");
118 } catch (IOException e) {
Laszlo Csomorc60be002019-04-04 07:36:05 -0700119 assertThat(e.getMessage()).contains("path does not exist");
Laszlo Csomor4fca9882016-09-02 09:48:42 +0000120 }
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 Csomor94d90582016-09-08 15:08:00 +0000137
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 Csomorc60be002019-04-04 07:36:05 -0700145 assertThat(WindowsFileOperations.isSymlinkOrJunction(linkPath.getAbsolutePath())).isTrue();
Laszlo Csomor94d90582016-09-08 15:08:00 +0000146
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 Csomorc60be002019-04-04 07:36:05 -0700152 assertThat(WindowsFileOperations.isSymlinkOrJunction(linkPath.getAbsolutePath())).isTrue();
Laszlo Csomor94d90582016-09-08 15:08:00 +0000153 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 Csomoraa1614b2016-12-15 11:16:44 +0000162
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 Csomorc60be002019-04-04 07:36:05 -0700171 assertThat(WindowsFileOperations.isSymlinkOrJunction(longPath)).isFalse();
172 assertThat(WindowsFileOperations.isSymlinkOrJunction(shortPath)).isFalse();
Laszlo Csomoraa1614b2016-12-15 11:16:44 +0000173
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 Csomorc60be002019-04-04 07:36:05 -0700178 assertThat(WindowsFileOperations.isSymlinkOrJunction(longPath)).isTrue();
179 assertThat(WindowsFileOperations.isSymlinkOrJunction(shortPath)).isTrue();
Laszlo Csomoraa1614b2016-12-15 11:16:44 +0000180
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 Csomorc60be002019-04-04 07:36:05 -0700185 assertThat(WindowsFileOperations.isSymlinkOrJunction(longPath)).isFalse();
186 assertThat(WindowsFileOperations.isSymlinkOrJunction(shortPath)).isFalse();
Laszlo Csomoraa1614b2016-12-15 11:16:44 +0000187 }
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 Csomor84aaca12019-01-24 05:33:21 -0800219 assertThat(WindowsFileOperations.getLongPath(longPath)).endsWith("will.exist/helloworld.txt");
220 assertThat(WindowsFileOperations.getLongPath(shortPath)).endsWith("will.exist/helloworld.txt");
Laszlo Csomoraa1614b2016-12-15 11:16:44 +0000221
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 Csomor84aaca12019-01-24 05:33:21 -0800247 .endsWith("will.exist_again/hellowelt.txt");
Laszlo Csomoraa1614b2016-12-15 11:16:44 +0000248 assertThat(WindowsFileOperations.getLongPath(foo + "\\will.exist_again\\hellowelt.txt"))
Laszlo Csomor84aaca12019-01-24 05:33:21 -0800249 .endsWith("will.exist_again/hellowelt.txt");
Laszlo Csomoraa1614b2016-12-15 11:16:44 +0000250 try {
251 WindowsFileOperations.getLongPath(longPath);
252 fail("expected to throw");
253 } catch (IOException e) {
254 assertThat(e.getMessage()).contains("GetLongPathName");
255 }
256 }
Laszlo Csomor4fca9882016-09-02 09:48:42 +0000257}