@@ -6,29 +6,56 @@ import spock.lang.Unroll
6
6
7
7
import java.nio.file.Files
8
8
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
9
13
10
14
@Unroll
11
15
class PathExtensionsTest extends Specification {
12
16
@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
+ }
18
30
19
31
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 )
26
58
}
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 )
32
59
}
33
60
34
61
def " canCreateDirectory" () {
@@ -39,20 +66,33 @@ class PathExtensionsTest extends Specification {
39
66
40
67
where :
41
68
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.
52
86
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
54
89
tmpdir. resolve(" with space" ) | true
90
+
91
+ // Config/data directories should be fine.
55
92
CoderCLIManager . getConfigDir() | true
56
93
CoderCLIManager . getDataDir() | true
94
+
95
+ // Relative paths can work as well.
96
+ Path . of(" relative/to/project" ) | true
57
97
}
58
98
}
0 commit comments