@@ -6,29 +6,54 @@ 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.*
9
10
10
11
@Unroll
11
12
class PathExtensionsTest extends Specification {
12
13
@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" )
14
+ private Path tmpdir = Path . of(System . getProperty(" java.io.tmpdir" )). resolve(" coder-gateway-test/path-extensions/" )
15
+
16
+ private void setPermissions (Path file ) {
17
+ AclFileAttributeView view = Files . getFileAttributeView(file, AclFileAttributeView . class)
18
+ UserPrincipal user = view. getOwner()
19
+ AclEntry entry = AclEntry . newBuilder()
20
+ .setType(AclEntryType . DENY )
21
+ .setPrincipal(user)
22
+ .setPermissions(AclEntryPermission . WRITE_DATA )
23
+ .build();
24
+ List<AclEntry > acl = view. getAcl()
25
+ acl. set(0 , entry)
26
+ view. setAcl(acl)
27
+ }
18
28
19
29
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()
30
+ // Clean up from the last run, if any.
31
+ tmpdir. toFile(). deleteDir()
32
+
33
+ // Push out the test files.
34
+ for (String dir in [" read-only-dir" , " no-permissions-dir" ]) {
35
+ Files . createDirectories(tmpdir. resolve(dir))
36
+ tmpdir. resolve(dir). resolve(" file" ). toFile(). write(" " )
37
+ }
38
+ for (String file in [" read-only-file" , " writable-file" , " no-permissions-file" ]) {
39
+ tmpdir. resolve(file). toFile(). write(" " )
40
+ }
41
+
42
+ // On Windows `File.setWritable()` only sets read-only, not permissions
43
+ // so on other platforms "read-only" is the same as "no permissions".
44
+ tmpdir. resolve(" read-only-file" ). toFile(). setWritable(false )
45
+ tmpdir. resolve(" read-only-dir" ). toFile(). setWritable(false )
46
+
47
+ // Create files without actual write permissions on Windows (not just
48
+ // read-only). On other platforms this is the same as above.
49
+ tmpdir. resolve(" no-permissions-dir/file" ). toFile(). write(" " )
50
+ if (System . getProperty(" os.name" ). toLowerCase(). contains(" windows" )) {
51
+ setPermissions(tmpdir. resolve(" no-permissions-file" ))
52
+ setPermissions(tmpdir. resolve(" no-permissions-dir" ))
53
+ } else {
54
+ tmpdir. resolve(" no-permissions-file" ). toFile(). setWritable(false )
55
+ tmpdir. resolve(" no-permissions-dir" ). toFile(). setWritable(false )
26
56
}
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
57
}
33
58
34
59
def " canCreateDirectory" () {
@@ -39,20 +64,33 @@ class PathExtensionsTest extends Specification {
39
64
40
65
where :
41
66
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
67
+ // A file is not valid for directory creation regardless of writability.
68
+ tmpdir. resolve(" read-only-file" ) | false
69
+ tmpdir. resolve(" read-only-file/nested/under/file" ) | false
70
+ tmpdir. resolve(" writable-file" ) | false
71
+ tmpdir. resolve(" writable-file/nested/under/file" ) | false
72
+ tmpdir. resolve(" read-only-dir/file" ) | false
73
+ tmpdir. resolve(" no-permissions-dir/file" ) | false
74
+
75
+ // Window: can create under read-only directories.
76
+ tmpdir. resolve(" read-only-dir" ) | System . getProperty(" os.name" ). toLowerCase(). contains(" windows" )
77
+ tmpdir. resolve(" read-only-dir/nested/under/dir" ) | System . getProperty(" os.name" ). toLowerCase(). contains(" windows" )
78
+
79
+ // Cannot create under a directory without permissions.
80
+ tmpdir. resolve(" no-permissions-dir" ) | false
81
+ tmpdir. resolve(" no-permissions-dir/nested/under/dir" ) | false
82
+
83
+ // Can create under a writable directory.
52
84
tmpdir | true
53
- tmpdir. resolve(" some/nested/non-existent/path" ) | true
85
+ tmpdir. resolve(" ./foo/bar/../../coder-gateway-test/path-extensions" ) | true
86
+ tmpdir. resolve(" nested/under/dir" ) | true
54
87
tmpdir. resolve(" with space" ) | true
88
+
89
+ // Config/data directories should be fine.
55
90
CoderCLIManager . getConfigDir() | true
56
91
CoderCLIManager . getDataDir() | true
92
+
93
+ // Relative paths can work as well.
94
+ Path . of(" relative/to/project" ) | true
57
95
}
58
96
}
0 commit comments