1 package afero
2
3 import (
4 "bytes"
5 "fmt"
6 "io"
7 "os"
8 "testing"
9 "time"
10 )
11
12 var tempDirs []string
13
14 func NewTempOsBaseFs(t *testing.T) Fs {
15 name, err := TempDir(NewOsFs(), "", "")
16 if err != nil {
17 t.Error("error creating tempDir", err)
18 }
19
20 tempDirs = append(tempDirs, name)
21
22 return NewBasePathFs(NewOsFs(), name)
23 }
24
25 func CleanupTempDirs(t *testing.T) {
26 osfs := NewOsFs()
27 type ev struct {
28 path string
29 e error
30 }
31
32 errs := []ev{}
33
34 for _, x := range tempDirs {
35 err := osfs.RemoveAll(x)
36 if err != nil {
37 errs = append(errs, ev{path: x, e: err})
38 }
39 }
40
41 for _, e := range errs {
42 fmt.Println("error removing tempDir", e.path, e.e)
43 }
44
45 if len(errs) > 0 {
46 t.Error("error cleaning up tempDirs")
47 }
48 tempDirs = []string{}
49 }
50
51 func TestUnionCreateExisting(t *testing.T) {
52 base := &MemMapFs{}
53 roBase := &ReadOnlyFs{source: base}
54 ufs := NewCopyOnWriteFs(roBase, &MemMapFs{})
55
56 base.MkdirAll("/home/test", 0o777)
57 fh, _ := base.Create("/home/test/file.txt")
58 fh.WriteString("This is a test")
59 fh.Close()
60
61 fh, err := ufs.OpenFile("/home/test/file.txt", os.O_RDWR, 0o666)
62 if err != nil {
63 t.Errorf("Failed to open file r/w: %s", err)
64 }
65
66 _, err = fh.Write([]byte("####"))
67 if err != nil {
68 t.Errorf("Failed to write file: %s", err)
69 }
70 fh.Seek(0, 0)
71 data, err := io.ReadAll(fh)
72 if err != nil {
73 t.Errorf("Failed to read file: %s", err)
74 }
75 if string(data) != "#### is a test" {
76 t.Errorf("Got wrong data")
77 }
78 fh.Close()
79
80 fh, _ = base.Open("/home/test/file.txt")
81 data, _ = io.ReadAll(fh)
82 if string(data) != "This is a test" {
83 t.Errorf("Got wrong data in base file")
84 }
85 fh.Close()
86
87 fh, err = ufs.Create("/home/test/file.txt")
88 switch err {
89 case nil:
90 if fi, _ := fh.Stat(); fi.Size() != 0 {
91 t.Errorf("Create did not truncate file")
92 }
93 fh.Close()
94 default:
95 t.Errorf("Create failed on existing file")
96 }
97 }
98
99 func TestUnionMergeReaddir(t *testing.T) {
100 base := &MemMapFs{}
101 roBase := &ReadOnlyFs{source: base}
102
103 ufs := &CopyOnWriteFs{base: roBase, layer: &MemMapFs{}}
104
105 base.MkdirAll("/home/test", 0o777)
106 fh, _ := base.Create("/home/test/file.txt")
107 fh.WriteString("This is a test")
108 fh.Close()
109
110 fh, _ = ufs.Create("/home/test/file2.txt")
111 fh.WriteString("This is a test")
112 fh.Close()
113
114 fh, _ = ufs.Open("/home/test")
115 files, err := fh.Readdirnames(-1)
116 if err != nil {
117 t.Errorf("Readdirnames failed")
118 }
119 if len(files) != 2 {
120 t.Errorf("Got wrong number of files: %v", files)
121 }
122 }
123
124 func TestExistingDirectoryCollisionReaddir(t *testing.T) {
125 base := &MemMapFs{}
126 roBase := &ReadOnlyFs{source: base}
127 overlay := &MemMapFs{}
128
129 ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
130
131 base.MkdirAll("/home/test", 0o777)
132 fh, _ := base.Create("/home/test/file.txt")
133 fh.WriteString("This is a test")
134 fh.Close()
135
136 overlay.MkdirAll("home/test", 0o777)
137 fh, _ = overlay.Create("/home/test/file2.txt")
138 fh.WriteString("This is a test")
139 fh.Close()
140
141 fh, _ = ufs.Create("/home/test/file3.txt")
142 fh.WriteString("This is a test")
143 fh.Close()
144
145 fh, _ = ufs.Open("/home/test")
146 files, err := fh.Readdirnames(-1)
147 if err != nil {
148 t.Errorf("Readdirnames failed")
149 }
150 if len(files) != 3 {
151 t.Errorf("Got wrong number of files in union: %v", files)
152 }
153
154 fh, _ = overlay.Open("/home/test")
155 files, err = fh.Readdirnames(-1)
156 if err != nil {
157 t.Errorf("Readdirnames failed")
158 }
159 if len(files) != 2 {
160 t.Errorf("Got wrong number of files in overlay: %v", files)
161 }
162 }
163
164 func TestNestedDirBaseReaddir(t *testing.T) {
165 base := &MemMapFs{}
166 roBase := &ReadOnlyFs{source: base}
167 overlay := &MemMapFs{}
168
169 ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
170
171 base.MkdirAll("/home/test/foo/bar", 0o777)
172 fh, _ := base.Create("/home/test/file.txt")
173 fh.WriteString("This is a test")
174 fh.Close()
175
176 fh, _ = base.Create("/home/test/foo/file2.txt")
177 fh.WriteString("This is a test")
178 fh.Close()
179 fh, _ = base.Create("/home/test/foo/bar/file3.txt")
180 fh.WriteString("This is a test")
181 fh.Close()
182
183 overlay.MkdirAll("/", 0o777)
184
185
186 fh, _ = ufs.Open("/home/test/foo")
187 list, err := fh.Readdir(-1)
188 if err != nil {
189 t.Errorf("Readdir failed %s", err)
190 }
191 if len(list) != 2 {
192 for _, x := range list {
193 fmt.Println(x.Name())
194 }
195 t.Errorf("Got wrong number of files in union: %v", len(list))
196 }
197 }
198
199 func TestNestedDirOverlayReaddir(t *testing.T) {
200 base := &MemMapFs{}
201 roBase := &ReadOnlyFs{source: base}
202 overlay := &MemMapFs{}
203
204 ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
205
206 base.MkdirAll("/", 0o777)
207 overlay.MkdirAll("/home/test/foo/bar", 0o777)
208 fh, _ := overlay.Create("/home/test/file.txt")
209 fh.WriteString("This is a test")
210 fh.Close()
211 fh, _ = overlay.Create("/home/test/foo/file2.txt")
212 fh.WriteString("This is a test")
213 fh.Close()
214 fh, _ = overlay.Create("/home/test/foo/bar/file3.txt")
215 fh.WriteString("This is a test")
216 fh.Close()
217
218
219 fh, _ = ufs.Open("/home/test/foo")
220 list, err := fh.Readdir(-1)
221 if err != nil {
222 t.Errorf("Readdir failed %s", err)
223 }
224 if len(list) != 2 {
225 for _, x := range list {
226 fmt.Println(x.Name())
227 }
228 t.Errorf("Got wrong number of files in union: %v", len(list))
229 }
230 }
231
232 func TestNestedDirOverlayOsFsReaddir(t *testing.T) {
233 defer CleanupTempDirs(t)
234 base := NewTempOsBaseFs(t)
235 roBase := &ReadOnlyFs{source: base}
236 overlay := NewTempOsBaseFs(t)
237
238 ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
239
240 base.MkdirAll("/", 0o777)
241 overlay.MkdirAll("/home/test/foo/bar", 0o777)
242 fh, _ := overlay.Create("/home/test/file.txt")
243 fh.WriteString("This is a test")
244 fh.Close()
245 fh, _ = overlay.Create("/home/test/foo/file2.txt")
246 fh.WriteString("This is a test")
247 fh.Close()
248 fh, _ = overlay.Create("/home/test/foo/bar/file3.txt")
249 fh.WriteString("This is a test")
250 fh.Close()
251
252
253 fh, _ = ufs.Open("/home/test/foo")
254 list, err := fh.Readdir(-1)
255 fh.Close()
256 if err != nil {
257 t.Errorf("Readdir failed %s", err)
258 }
259 if len(list) != 2 {
260 for _, x := range list {
261 fmt.Println(x.Name())
262 }
263 t.Errorf("Got wrong number of files in union: %v", len(list))
264 }
265 }
266
267 func TestCopyOnWriteFsWithOsFs(t *testing.T) {
268 defer CleanupTempDirs(t)
269 base := NewTempOsBaseFs(t)
270 roBase := &ReadOnlyFs{source: base}
271 overlay := NewTempOsBaseFs(t)
272
273 ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
274
275 base.MkdirAll("/home/test", 0o777)
276 fh, _ := base.Create("/home/test/file.txt")
277 fh.WriteString("This is a test")
278 fh.Close()
279
280 overlay.MkdirAll("home/test", 0o777)
281 fh, _ = overlay.Create("/home/test/file2.txt")
282 fh.WriteString("This is a test")
283 fh.Close()
284
285 fh, _ = ufs.Create("/home/test/file3.txt")
286 fh.WriteString("This is a test")
287 fh.Close()
288
289 fh, _ = ufs.Open("/home/test")
290 files, err := fh.Readdirnames(-1)
291 fh.Close()
292 if err != nil {
293 t.Errorf("Readdirnames failed")
294 }
295 if len(files) != 3 {
296 t.Errorf("Got wrong number of files in union: %v", files)
297 }
298
299 fh, _ = overlay.Open("/home/test")
300 files, err = fh.Readdirnames(-1)
301 fh.Close()
302 if err != nil {
303 t.Errorf("Readdirnames failed")
304 }
305 if len(files) != 2 {
306 t.Errorf("Got wrong number of files in overlay: %v", files)
307 }
308 }
309
310 func TestUnionCacheWrite(t *testing.T) {
311 base := &MemMapFs{}
312 layer := &MemMapFs{}
313
314 ufs := NewCacheOnReadFs(base, layer, 0)
315
316 base.Mkdir("/data", 0o777)
317
318 fh, err := ufs.Create("/data/file.txt")
319 if err != nil {
320 t.Errorf("Failed to create file")
321 }
322 _, err = fh.Write([]byte("This is a test"))
323 if err != nil {
324 t.Errorf("Failed to write file")
325 }
326
327 fh.Seek(0, io.SeekStart)
328 buf := make([]byte, 4)
329 _, _ = fh.Read(buf)
330 fh.Write([]byte(" IS A"))
331 fh.Close()
332
333 baseData, _ := ReadFile(base, "/data/file.txt")
334 layerData, _ := ReadFile(layer, "/data/file.txt")
335 if string(baseData) != string(layerData) {
336 t.Errorf("Different data: %s <=> %s", baseData, layerData)
337 }
338 }
339
340 func TestUnionCacheExpire(t *testing.T) {
341 base := &MemMapFs{}
342 layer := &MemMapFs{}
343 ufs := &CacheOnReadFs{base: base, layer: layer, cacheTime: 1 * time.Second}
344
345 base.Mkdir("/data", 0o777)
346
347 fh, err := ufs.Create("/data/file.txt")
348 if err != nil {
349 t.Errorf("Failed to create file")
350 }
351 _, err = fh.Write([]byte("This is a test"))
352 if err != nil {
353 t.Errorf("Failed to write file")
354 }
355 fh.Close()
356
357 fh, _ = base.Create("/data/file.txt")
358
359 time.Sleep(2 * time.Second)
360 fh.WriteString("Another test")
361 fh.Close()
362
363 data, _ := ReadFile(ufs, "/data/file.txt")
364 if string(data) != "Another test" {
365 t.Errorf("cache time failed: <%s>", data)
366 }
367 }
368
369 func TestCacheOnReadFsNotInLayer(t *testing.T) {
370 base := NewMemMapFs()
371 layer := NewMemMapFs()
372 fs := NewCacheOnReadFs(base, layer, 0)
373
374 fh, err := base.Create("/file.txt")
375 if err != nil {
376 t.Fatal("unable to create file: ", err)
377 }
378
379 txt := []byte("This is a test")
380 fh.Write(txt)
381 fh.Close()
382
383 fh, err = fs.Open("/file.txt")
384 if err != nil {
385 t.Fatal("could not open file: ", err)
386 }
387
388 b, err := ReadAll(fh)
389 fh.Close()
390
391 if err != nil {
392 t.Fatal("could not read file: ", err)
393 } else if !bytes.Equal(txt, b) {
394 t.Fatalf("wanted file text %q, got %q", txt, b)
395 }
396
397 fh, err = layer.Open("/file.txt")
398 if err != nil {
399 t.Fatal("could not open file from layer: ", err)
400 }
401 fh.Close()
402 }
403
404
405 func TestUnionFileReaddirEmpty(t *testing.T) {
406 osFs := NewOsFs()
407
408 base := NewMemMapFs()
409 overlay := NewMemMapFs()
410 ufs := &CopyOnWriteFs{base: base, layer: overlay}
411 mem := NewMemMapFs()
412
413
414 for _, fs := range []Fs{osFs, ufs, mem} {
415 baseDir, err := TempDir(fs, "", "empty-dir")
416 if err != nil {
417 t.Fatal(err)
418 }
419
420 f, err := fs.Open(baseDir)
421 if err != nil {
422 t.Fatal(err)
423 }
424
425 names, err := f.Readdirnames(1)
426 if err != io.EOF {
427 t.Fatal(err)
428 }
429
430 if len(names) != 0 {
431 t.Fatal("should be empty")
432 }
433
434 f.Close()
435
436 fs.RemoveAll(baseDir)
437 }
438 }
439
440
441 func TestUnionFileReaddirDuplicateEmpty(t *testing.T) {
442 base := NewMemMapFs()
443 dir, err := TempDir(base, "", "empty-dir")
444 if err != nil {
445 t.Fatal(err)
446 }
447
448
449 overlay := NewMemMapFs()
450 err = overlay.Mkdir(dir, 0o700)
451 if err != nil {
452 t.Fatal(err)
453 }
454
455 ufs := &CopyOnWriteFs{base: base, layer: overlay}
456
457 f, err := ufs.Open(dir)
458 if err != nil {
459 t.Fatal(err)
460 }
461 defer f.Close()
462
463 names, err := f.Readdirnames(0)
464
465 if err == io.EOF {
466 t.Errorf("unexpected io.EOF error")
467 }
468
469 if len(names) != 0 {
470 t.Fatal("should be empty")
471 }
472 }
473
474 func TestUnionFileReaddirAskForTooMany(t *testing.T) {
475 base := &MemMapFs{}
476 overlay := &MemMapFs{}
477
478 const testFiles = 5
479 for i := 0; i < testFiles; i++ {
480 WriteFile(base, fmt.Sprintf("file%d.txt", i), []byte("afero"), 0o777)
481 }
482
483 ufs := &CopyOnWriteFs{base: base, layer: overlay}
484
485 f, err := ufs.Open("")
486 if err != nil {
487 t.Fatal(err)
488 }
489
490 defer f.Close()
491
492
493 wantNames := 3
494 names, err := f.Readdirnames(wantNames)
495 if err != nil {
496 t.Fatal(err)
497 }
498 if len(names) != wantNames {
499 t.Fatalf("got %d names %v, want %d", len(names), names, wantNames)
500 }
501
502
503 wantNames = testFiles - len(names)
504 names, err = f.Readdirnames(wantNames + 1)
505 if err != nil {
506 t.Fatal(err)
507 }
508 if len(names) != wantNames {
509 t.Fatalf("got %d names %v, want %d", len(names), names, wantNames)
510 }
511
512
513 _, err = f.Readdirnames(3)
514 if err != io.EOF {
515 t.Fatal(err)
516 }
517 }
518
View as plain text