Skip to content

Commit 6f0024b

Browse files
committed
Add real permission tests for Windows
1 parent 8622810 commit 6f0024b

File tree

1 file changed

+67
-27
lines changed

1 file changed

+67
-27
lines changed

src/test/groovy/PathExtensionsTest.groovy

Lines changed: 67 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,56 @@ import spock.lang.Unroll
66

77
import java.nio.file.Files
88
import java.nio.file.Path
9+
import java.nio.file.attribute.AclEntry
10+
import java.nio.file.attribute.AclEntryPermission
11+
import java.nio.file.attribute.AclEntryType
12+
import java.nio.file.attribute.AclFileAttributeView
913

1014
@Unroll
1115
class PathExtensionsTest extends Specification {
1216
@Shared
13-
private Path tmpdir = Path.of(System.getProperty("java.io.tmpdir"))
14-
@Shared
15-
private Path unwritableFile = tmpdir.resolve("coder-gateway-test/path-extensions/unwritable/file")
16-
@Shared
17-
private Path writableFile = tmpdir.resolve("coder-gateway-test/path-extensions/writable-file")
17+
private Path tmpdir = Path.of(System.getProperty("java.io.tmpdir")).resolve("coder-gateway-test/path-extensions/")
18+
19+
private void setWindowsPermissions(Path file) {
20+
AclFileAttributeView view = Files.getFileAttributeView(file, AclFileAttributeView.class)
21+
AclEntry entry = AclEntry.newBuilder()
22+
.setType(AclEntryType.DENY)
23+
.setPrincipal(view.getOwner())
24+
.setPermissions(AclEntryPermission.WRITE_DATA)
25+
.build()
26+
List<AclEntry> acl = view.getAcl()
27+
acl.set(0, entry)
28+
view.setAcl(acl)
29+
}
1830

1931
void setupSpec() {
20-
// TODO: On Windows setWritable() only sets read-only; how do we set
21-
// actual permissions? Initially I tried an existing dir like WINDIR
22-
// which worked locally but in CI that is writable for some reason.
23-
if (unwritableFile.parent.toFile().exists()) {
24-
unwritableFile.parent.toFile().setWritable(true)
25-
unwritableFile.parent.toFile().deleteDir()
32+
// Clean up from the last run, if any.
33+
tmpdir.toFile().deleteDir()
34+
35+
// Push out the test files.
36+
for (String dir in ["read-only-dir", "no-permissions-dir"]) {
37+
Files.createDirectories(tmpdir.resolve(dir))
38+
tmpdir.resolve(dir).resolve("file").toFile().write("")
39+
}
40+
for (String file in ["read-only-file", "writable-file", "no-permissions-file"]) {
41+
tmpdir.resolve(file).toFile().write("")
42+
}
43+
44+
// On Windows `File.setWritable()` only sets read-only, not permissions
45+
// so on other platforms "read-only" is the same as "no permissions".
46+
tmpdir.resolve("read-only-file").toFile().setWritable(false)
47+
tmpdir.resolve("read-only-dir").toFile().setWritable(false)
48+
49+
// Create files without actual write permissions on Windows (not just
50+
// read-only). On other platforms this is the same as above.
51+
tmpdir.resolve("no-permissions-dir/file").toFile().write("")
52+
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
53+
setWindowsPermissions(tmpdir.resolve("no-permissions-file"))
54+
setWindowsPermissions(tmpdir.resolve("no-permissions-dir"))
55+
} else {
56+
tmpdir.resolve("no-permissions-file").toFile().setWritable(false)
57+
tmpdir.resolve("no-permissions-dir").toFile().setWritable(false)
2658
}
27-
Files.createDirectories(unwritableFile.parent)
28-
unwritableFile.toFile().write("text")
29-
writableFile.toFile().write("text")
30-
unwritableFile.toFile().setWritable(false)
31-
unwritableFile.parent.toFile().setWritable(false)
3259
}
3360

3461
def "canCreateDirectory"() {
@@ -39,20 +66,33 @@ class PathExtensionsTest extends Specification {
3966

4067
where:
4168
path | expected
42-
unwritableFile | false
43-
unwritableFile.resolve("probably/nonexistent") | false
44-
// TODO: Java reports read-only directories on Windows as writable.
45-
unwritableFile.parent.resolve("probably/nonexistent") | System.getProperty("os.name").toLowerCase().contains("windows")
46-
writableFile | false
47-
writableFile.parent | true
48-
writableFile.resolve("nested/under/file") | false
49-
writableFile.parent.resolve("nested/under/dir") | true
50-
Path.of("relative to project") | true
51-
tmpdir.resolve("./foo/bar/../../coder-gateway-test/path-extensions") | true
69+
// A file is not valid for directory creation regardless of writability.
70+
tmpdir.resolve("read-only-file") | false
71+
tmpdir.resolve("read-only-file/nested/under/file") | false
72+
tmpdir.resolve("writable-file") | false
73+
tmpdir.resolve("writable-file/nested/under/file") | false
74+
tmpdir.resolve("read-only-dir/file") | false
75+
tmpdir.resolve("no-permissions-dir/file") | false
76+
77+
// Window: can create under read-only directories.
78+
tmpdir.resolve("read-only-dir") | System.getProperty("os.name").toLowerCase().contains("windows")
79+
tmpdir.resolve("read-only-dir/nested/under/dir") | System.getProperty("os.name").toLowerCase().contains("windows")
80+
81+
// Cannot create under a directory without permissions.
82+
tmpdir.resolve("no-permissions-dir") | false
83+
tmpdir.resolve("no-permissions-dir/nested/under/dir") | false
84+
85+
// Can create under a writable directory.
5286
tmpdir | true
53-
tmpdir.resolve("some/nested/non-existent/path") | true
87+
tmpdir.resolve("./foo/bar/../../coder-gateway-test/path-extensions") | true
88+
tmpdir.resolve("nested/under/dir") | true
5489
tmpdir.resolve("with space") | true
90+
91+
// Config/data directories should be fine.
5592
CoderCLIManager.getConfigDir() | true
5693
CoderCLIManager.getDataDir() | true
94+
95+
// Relative paths can work as well.
96+
Path.of("relative/to/project") | true
5797
}
5898
}

0 commit comments

Comments
 (0)