1
1
package agent_test
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
5
6
"io"
6
7
"net/http"
@@ -10,6 +11,7 @@ import (
10
11
11
12
"github.com/spf13/afero"
12
13
"github.com/stretchr/testify/require"
14
+ "golang.org/x/xerrors"
13
15
14
16
"github.com/coder/coder/v2/agent"
15
17
"github.com/coder/coder/v2/agent/agenttest"
@@ -38,6 +40,40 @@ func (fs *testFs) Open(name string) (afero.File, error) {
38
40
return fs .Fs .Open (name )
39
41
}
40
42
43
+ func (fs * testFs ) Create (name string ) (afero.File , error ) {
44
+ if err := fs .intercept ("create" , name ); err != nil {
45
+ return nil , err
46
+ }
47
+ // Unlike os, afero lets you create files where directories already exist and
48
+ // lets you nest them underneath files, somehow.
49
+ stat , err := fs .Fs .Stat (name )
50
+ if err == nil && stat .IsDir () {
51
+ return nil , xerrors .New ("is a directory" )
52
+ }
53
+ stat , err = fs .Fs .Stat (filepath .Dir (name ))
54
+ if err == nil && ! stat .IsDir () {
55
+ return nil , xerrors .New ("not a directory" )
56
+ }
57
+ return fs .Fs .Create (name )
58
+ }
59
+
60
+ func (fs * testFs ) MkdirAll (name string , mode os.FileMode ) error {
61
+ if err := fs .intercept ("mkdirall" , name ); err != nil {
62
+ return err
63
+ }
64
+ // Unlike os, afero lets you create directories where files already exist and
65
+ // lets you nest them underneath files somehow.
66
+ stat , err := fs .Fs .Stat (filepath .Dir (name ))
67
+ if err == nil && ! stat .IsDir () {
68
+ return xerrors .New ("not a directory" )
69
+ }
70
+ stat , err = fs .Fs .Stat (name )
71
+ if err == nil && ! stat .IsDir () {
72
+ return xerrors .New ("not a directory" )
73
+ }
74
+ return fs .Fs .MkdirAll (name , mode )
75
+ }
76
+
41
77
func TestReadFile (t * testing.T ) {
42
78
t .Parallel ()
43
79
@@ -214,3 +250,107 @@ func TestReadFile(t *testing.T) {
214
250
})
215
251
}
216
252
}
253
+
254
+ func TestWriteFile (t * testing.T ) {
255
+ t .Parallel ()
256
+
257
+ tmpdir := os .TempDir ()
258
+ noPermsFilePath := filepath .Join (tmpdir , "no-perms-file" )
259
+ noPermsDirPath := filepath .Join (tmpdir , "no-perms-dir" )
260
+ //nolint:dogsled
261
+ conn , _ , _ , fs , _ := setupAgent (t , agentsdk.Manifest {}, 0 , func (_ * agenttest.Client , opts * agent.Options ) {
262
+ opts .Filesystem = newTestFs (opts .Filesystem , func (call , file string ) error {
263
+ if file == noPermsFilePath || file == noPermsDirPath {
264
+ return os .ErrPermission
265
+ }
266
+ return nil
267
+ })
268
+ })
269
+
270
+ dirPath := filepath .Join (tmpdir , "directory" )
271
+ err := fs .MkdirAll (dirPath , 0o755 )
272
+ require .NoError (t , err )
273
+
274
+ filePath := filepath .Join (tmpdir , "file" )
275
+ err = afero .WriteFile (fs , filePath , []byte ("content" ), 0o644 )
276
+ require .NoError (t , err )
277
+
278
+ tests := []struct {
279
+ name string
280
+ path string
281
+ bytes []byte
282
+ errCode int
283
+ error string
284
+ }{
285
+ {
286
+ name : "NoPath" ,
287
+ path : "" ,
288
+ errCode : http .StatusBadRequest ,
289
+ error : "\" path\" is required" ,
290
+ },
291
+ {
292
+ name : "RelativePath" ,
293
+ path : "./relative" ,
294
+ errCode : http .StatusBadRequest ,
295
+ error : "file path must be absolute" ,
296
+ },
297
+ {
298
+ name : "RelativePath" ,
299
+ path : "also-relative" ,
300
+ errCode : http .StatusBadRequest ,
301
+ error : "file path must be absolute" ,
302
+ },
303
+ {
304
+ name : "NonExistent" ,
305
+ path : filepath .Join (tmpdir , "/nested/does-not-exist" ),
306
+ bytes : []byte ("now it does exist" ),
307
+ },
308
+ {
309
+ name : "IsDir" ,
310
+ path : dirPath ,
311
+ errCode : http .StatusBadRequest ,
312
+ error : "is a directory" ,
313
+ },
314
+ {
315
+ name : "IsNotDir" ,
316
+ path : filepath .Join (filePath , "file2" ),
317
+ errCode : http .StatusBadRequest ,
318
+ error : "not a directory" ,
319
+ },
320
+ {
321
+ name : "NoPermissionsFile" ,
322
+ path : noPermsFilePath ,
323
+ errCode : http .StatusForbidden ,
324
+ error : "permission denied" ,
325
+ },
326
+ {
327
+ name : "NoPermissionsDir" ,
328
+ path : filepath .Join (noPermsDirPath , "within-no-perm-dir" ),
329
+ errCode : http .StatusForbidden ,
330
+ error : "permission denied" ,
331
+ },
332
+ }
333
+
334
+ for _ , tt := range tests {
335
+ t .Run (tt .name , func (t * testing.T ) {
336
+ t .Parallel ()
337
+
338
+ ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitLong )
339
+ defer cancel ()
340
+
341
+ reader := bytes .NewReader (tt .bytes )
342
+ err := conn .WriteFile (ctx , tt .path , reader )
343
+ if tt .errCode != 0 {
344
+ require .Error (t , err )
345
+ cerr := coderdtest .SDKError (t , err )
346
+ require .Contains (t , cerr .Error (), tt .error )
347
+ require .Equal (t , tt .errCode , cerr .StatusCode ())
348
+ } else {
349
+ require .NoError (t , err )
350
+ b , err := afero .ReadFile (fs , tt .path )
351
+ require .NoError (t , err )
352
+ require .Equal (t , tt .bytes , b )
353
+ }
354
+ })
355
+ }
356
+ }
0 commit comments