github.com/mferrell/afero@v1.8.3-0.20220319163648-1d8d1d1d8040/memmap_test.go (about) 1 package afero 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "path/filepath" 8 "runtime" 9 "testing" 10 "time" 11 ) 12 13 func TestNormalizePath(t *testing.T) { 14 type test struct { 15 input string 16 expected string 17 } 18 19 data := []test{ 20 {".", FilePathSeparator}, 21 {"./", FilePathSeparator}, 22 {"..", FilePathSeparator}, 23 {"../", FilePathSeparator}, 24 {"./..", FilePathSeparator}, 25 {"./../", FilePathSeparator}, 26 } 27 28 for i, d := range data { 29 cpath := normalizePath(d.input) 30 if d.expected != cpath { 31 t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, cpath) 32 } 33 } 34 } 35 36 func TestPathErrors(t *testing.T) { 37 path := filepath.Join(".", "some", "path") 38 path2 := filepath.Join(".", "different", "path") 39 fs := NewMemMapFs() 40 perm := os.FileMode(0755) 41 uid := 1000 42 gid := 1000 43 44 // relevant functions: 45 // func (m *MemMapFs) Chmod(name string, mode os.FileMode) error 46 // func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error 47 // func (m *MemMapFs) Create(name string) (File, error) 48 // func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error 49 // func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error 50 // func (m *MemMapFs) Open(name string) (File, error) 51 // func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) 52 // func (m *MemMapFs) Remove(name string) error 53 // func (m *MemMapFs) Rename(oldname, newname string) error 54 // func (m *MemMapFs) Stat(name string) (os.FileInfo, error) 55 56 err := fs.Chmod(path, perm) 57 checkPathError(t, err, "Chmod") 58 59 err = fs.Chown(path, uid, gid) 60 checkPathError(t, err, "Chown") 61 62 err = fs.Chtimes(path, time.Now(), time.Now()) 63 checkPathError(t, err, "Chtimes") 64 65 // fs.Create doesn't return an error 66 67 err = fs.Mkdir(path2, perm) 68 if err != nil { 69 t.Error(err) 70 } 71 err = fs.Mkdir(path2, perm) 72 checkPathError(t, err, "Mkdir") 73 74 err = fs.MkdirAll(path2, perm) 75 if err != nil { 76 t.Error("MkdirAll:", err) 77 } 78 79 _, err = fs.Open(path) 80 checkPathError(t, err, "Open") 81 82 _, err = fs.OpenFile(path, os.O_RDWR, perm) 83 checkPathError(t, err, "OpenFile") 84 85 err = fs.Remove(path) 86 checkPathError(t, err, "Remove") 87 88 err = fs.RemoveAll(path) 89 if err != nil { 90 t.Error("RemoveAll:", err) 91 } 92 93 err = fs.Rename(path, path2) 94 checkPathError(t, err, "Rename") 95 96 _, err = fs.Stat(path) 97 checkPathError(t, err, "Stat") 98 } 99 100 func checkPathError(t *testing.T, err error, op string) { 101 pathErr, ok := err.(*os.PathError) 102 if !ok { 103 t.Error(op+":", err, "is not a os.PathError") 104 return 105 } 106 _, ok = pathErr.Err.(*os.PathError) 107 if ok { 108 t.Error(op+":", err, "contains another os.PathError") 109 } 110 } 111 112 // Ensure os.O_EXCL is correctly handled. 113 func TestOpenFileExcl(t *testing.T) { 114 const fileName = "/myFileTest" 115 const fileMode = os.FileMode(0765) 116 117 fs := NewMemMapFs() 118 119 // First creation should succeed. 120 f, err := fs.OpenFile(fileName, os.O_CREATE|os.O_EXCL, fileMode) 121 if err != nil { 122 t.Errorf("OpenFile Create Excl failed: %s", err) 123 return 124 } 125 f.Close() 126 127 // Second creation should fail. 128 _, err = fs.OpenFile(fileName, os.O_CREATE|os.O_EXCL, fileMode) 129 if err == nil { 130 t.Errorf("OpenFile Create Excl should have failed, but it didn't") 131 } 132 checkPathError(t, err, "Open") 133 } 134 135 // Ensure Permissions are set on OpenFile/Mkdir/MkdirAll 136 func TestPermSet(t *testing.T) { 137 const fileName = "/myFileTest" 138 const dirPath = "/myDirTest" 139 const dirPathAll = "/my/path/to/dir" 140 141 const fileMode = os.FileMode(0765) 142 // directories will also have the directory bit set 143 const dirMode = fileMode | os.ModeDir 144 145 fs := NewMemMapFs() 146 147 // Test Openfile 148 f, err := fs.OpenFile(fileName, os.O_CREATE, fileMode) 149 if err != nil { 150 t.Errorf("OpenFile Create failed: %s", err) 151 return 152 } 153 f.Close() 154 155 s, err := fs.Stat(fileName) 156 if err != nil { 157 t.Errorf("Stat failed: %s", err) 158 return 159 } 160 if s.Mode().String() != fileMode.String() { 161 t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), fileMode.String()) 162 return 163 } 164 165 // Test Mkdir 166 err = fs.Mkdir(dirPath, dirMode) 167 if err != nil { 168 t.Errorf("MkDir Create failed: %s", err) 169 return 170 } 171 s, err = fs.Stat(dirPath) 172 if err != nil { 173 t.Errorf("Stat failed: %s", err) 174 return 175 } 176 // sets File 177 if s.Mode().String() != dirMode.String() { 178 t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), dirMode.String()) 179 return 180 } 181 182 // Test MkdirAll 183 err = fs.MkdirAll(dirPathAll, dirMode) 184 if err != nil { 185 t.Errorf("MkDir Create failed: %s", err) 186 return 187 } 188 s, err = fs.Stat(dirPathAll) 189 if err != nil { 190 t.Errorf("Stat failed: %s", err) 191 return 192 } 193 if s.Mode().String() != dirMode.String() { 194 t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), dirMode.String()) 195 return 196 } 197 } 198 199 // Fails if multiple file objects use the same file.at counter in MemMapFs 200 func TestMultipleOpenFiles(t *testing.T) { 201 defer removeAllTestFiles(t) 202 const fileName = "afero-demo2.txt" 203 204 var data = make([][]byte, len(Fss)) 205 206 for i, fs := range Fss { 207 dir := testDir(fs) 208 path := filepath.Join(dir, fileName) 209 fh1, err := fs.Create(path) 210 if err != nil { 211 t.Error("fs.Create failed: " + err.Error()) 212 } 213 _, err = fh1.Write([]byte("test")) 214 if err != nil { 215 t.Error("fh.Write failed: " + err.Error()) 216 } 217 _, err = fh1.Seek(0, os.SEEK_SET) 218 if err != nil { 219 t.Error(err) 220 } 221 222 fh2, err := fs.OpenFile(path, os.O_RDWR, 0777) 223 if err != nil { 224 t.Error("fs.OpenFile failed: " + err.Error()) 225 } 226 _, err = fh2.Seek(0, os.SEEK_END) 227 if err != nil { 228 t.Error(err) 229 } 230 _, err = fh2.Write([]byte("data")) 231 if err != nil { 232 t.Error(err) 233 } 234 err = fh2.Close() 235 if err != nil { 236 t.Error(err) 237 } 238 239 _, err = fh1.Write([]byte("data")) 240 if err != nil { 241 t.Error(err) 242 } 243 err = fh1.Close() 244 if err != nil { 245 t.Error(err) 246 } 247 // the file now should contain "datadata" 248 data[i], err = ReadFile(fs, path) 249 if err != nil { 250 t.Error(err) 251 } 252 } 253 254 for i, fs := range Fss { 255 if i == 0 { 256 continue 257 } 258 if string(data[0]) != string(data[i]) { 259 t.Errorf("%s and %s don't behave the same\n"+ 260 "%s: \"%s\"\n%s: \"%s\"\n", 261 Fss[0].Name(), fs.Name(), Fss[0].Name(), data[0], fs.Name(), data[i]) 262 } 263 } 264 } 265 266 // Test if file.Write() fails when opened as read only 267 func TestReadOnly(t *testing.T) { 268 defer removeAllTestFiles(t) 269 const fileName = "afero-demo.txt" 270 271 for _, fs := range Fss { 272 dir := testDir(fs) 273 path := filepath.Join(dir, fileName) 274 275 f, err := fs.Create(path) 276 if err != nil { 277 t.Error(fs.Name()+":", "fs.Create failed: "+err.Error()) 278 } 279 _, err = f.Write([]byte("test")) 280 if err != nil { 281 t.Error(fs.Name()+":", "Write failed: "+err.Error()) 282 } 283 f.Close() 284 285 f, err = fs.Open(path) 286 if err != nil { 287 t.Error("fs.Open failed: " + err.Error()) 288 } 289 _, err = f.Write([]byte("data")) 290 if err == nil { 291 t.Error(fs.Name()+":", "No write error") 292 } 293 f.Close() 294 295 f, err = fs.OpenFile(path, os.O_RDONLY, 0644) 296 if err != nil { 297 t.Error("fs.Open failed: " + err.Error()) 298 } 299 _, err = f.Write([]byte("data")) 300 if err == nil { 301 t.Error(fs.Name()+":", "No write error") 302 } 303 f.Close() 304 } 305 } 306 307 func TestWriteCloseTime(t *testing.T) { 308 defer removeAllTestFiles(t) 309 const fileName = "afero-demo.txt" 310 311 for _, fs := range Fss { 312 dir := testDir(fs) 313 path := filepath.Join(dir, fileName) 314 315 f, err := fs.Create(path) 316 if err != nil { 317 t.Error(fs.Name()+":", "fs.Create failed: "+err.Error()) 318 } 319 f.Close() 320 321 f, err = fs.Create(path) 322 if err != nil { 323 t.Error(fs.Name()+":", "fs.Create failed: "+err.Error()) 324 } 325 fi, err := f.Stat() 326 if err != nil { 327 t.Error(fs.Name()+":", "Stat failed: "+err.Error()) 328 } 329 timeBefore := fi.ModTime() 330 331 // sorry for the delay, but we have to make sure time advances, 332 // also on non Un*x systems... 333 switch runtime.GOOS { 334 case "windows": 335 time.Sleep(2 * time.Second) 336 case "darwin": 337 time.Sleep(1 * time.Second) 338 default: // depending on the FS, this may work with < 1 second, on my old ext3 it does not 339 time.Sleep(1 * time.Second) 340 } 341 342 _, err = f.Write([]byte("test")) 343 if err != nil { 344 t.Error(fs.Name()+":", "Write failed: "+err.Error()) 345 } 346 f.Close() 347 fi, err = fs.Stat(path) 348 if err != nil { 349 t.Error(fs.Name()+":", "fs.Stat failed: "+err.Error()) 350 } 351 if fi.ModTime().Equal(timeBefore) { 352 t.Error(fs.Name()+":", "ModTime was not set on Close()") 353 } 354 } 355 } 356 357 // This test should be run with the race detector on: 358 // go test -race -v -timeout 10s -run TestRacingDeleteAndClose 359 func TestRacingDeleteAndClose(t *testing.T) { 360 fs := NewMemMapFs() 361 pathname := "testfile" 362 f, err := fs.Create(pathname) 363 if err != nil { 364 t.Fatal(err) 365 } 366 367 in := make(chan bool) 368 369 go func() { 370 <-in 371 f.Close() 372 }() 373 go func() { 374 <-in 375 fs.Remove(pathname) 376 }() 377 close(in) 378 } 379 380 // This test should be run with the race detector on: 381 // go test -run TestMemFsDataRace -race 382 func TestMemFsDataRace(t *testing.T) { 383 const dir = "test_dir" 384 fs := NewMemMapFs() 385 386 if err := fs.MkdirAll(dir, 0777); err != nil { 387 t.Fatal(err) 388 } 389 390 const n = 1000 391 done := make(chan struct{}) 392 393 go func() { 394 defer close(done) 395 for i := 0; i < n; i++ { 396 fname := filepath.Join(dir, fmt.Sprintf("%d.txt", i)) 397 if err := WriteFile(fs, fname, []byte(""), 0777); err != nil { 398 panic(err) 399 } 400 if err := fs.Remove(fname); err != nil { 401 panic(err) 402 } 403 } 404 }() 405 406 loop: 407 for { 408 select { 409 case <-done: 410 break loop 411 default: 412 _, err := ReadDir(fs, dir) 413 if err != nil { 414 t.Fatal(err) 415 } 416 } 417 } 418 } 419 420 // root is a directory 421 func TestMemFsRootDirMode(t *testing.T) { 422 t.Parallel() 423 424 fs := NewMemMapFs() 425 info, err := fs.Stat("/") 426 if err != nil { 427 t.Fatal(err) 428 } 429 if !info.IsDir() { 430 t.Error("should be a directory") 431 } 432 if !info.Mode().IsDir() { 433 t.Errorf("FileMode is not directory, is %s", info.Mode().String()) 434 } 435 } 436 437 // MkdirAll creates intermediate directories with correct mode 438 func TestMemFsMkdirAllMode(t *testing.T) { 439 t.Parallel() 440 441 fs := NewMemMapFs() 442 err := fs.MkdirAll("/a/b/c", 0755) 443 if err != nil { 444 t.Fatal(err) 445 } 446 info, err := fs.Stat("/a") 447 if err != nil { 448 t.Fatal(err) 449 } 450 if !info.Mode().IsDir() { 451 t.Error("/a: mode is not directory") 452 } 453 if !info.ModTime().After(time.Now().Add(-1 * time.Hour)) { 454 t.Errorf("/a: mod time not set, got %s", info.ModTime()) 455 } 456 if info.Mode() != os.FileMode(os.ModeDir|0755) { 457 t.Errorf("/a: wrong permissions, expected drwxr-xr-x, got %s", info.Mode()) 458 } 459 info, err = fs.Stat("/a/b") 460 if err != nil { 461 t.Fatal(err) 462 } 463 if !info.Mode().IsDir() { 464 t.Error("/a/b: mode is not directory") 465 } 466 if info.Mode() != os.FileMode(os.ModeDir|0755) { 467 t.Errorf("/a/b: wrong permissions, expected drwxr-xr-x, got %s", info.Mode()) 468 } 469 if !info.ModTime().After(time.Now().Add(-1 * time.Hour)) { 470 t.Errorf("/a/b: mod time not set, got %s", info.ModTime()) 471 } 472 info, err = fs.Stat("/a/b/c") 473 if err != nil { 474 t.Fatal(err) 475 } 476 if !info.Mode().IsDir() { 477 t.Error("/a/b/c: mode is not directory") 478 } 479 if info.Mode() != os.FileMode(os.ModeDir|0755) { 480 t.Errorf("/a/b/c: wrong permissions, expected drwxr-xr-x, got %s", info.Mode()) 481 } 482 if !info.ModTime().After(time.Now().Add(-1 * time.Hour)) { 483 t.Errorf("/a/b/c: mod time not set, got %s", info.ModTime()) 484 } 485 } 486 487 // MkdirAll does not change permissions of already-existing directories 488 func TestMemFsMkdirAllNoClobber(t *testing.T) { 489 t.Parallel() 490 491 fs := NewMemMapFs() 492 err := fs.MkdirAll("/a/b/c", 0755) 493 if err != nil { 494 t.Fatal(err) 495 } 496 info, err := fs.Stat("/a/b") 497 if err != nil { 498 t.Fatal(err) 499 } 500 if info.Mode() != os.FileMode(os.ModeDir|0755) { 501 t.Errorf("/a/b: wrong permissions, expected drwxr-xr-x, got %s", info.Mode()) 502 } 503 err = fs.MkdirAll("/a/b/c/d/e/f", 0710) 504 // '/a/b' is unchanged 505 if err != nil { 506 t.Fatal(err) 507 } 508 info, err = fs.Stat("/a/b") 509 if err != nil { 510 t.Fatal(err) 511 } 512 if info.Mode() != os.FileMode(os.ModeDir|0755) { 513 t.Errorf("/a/b: wrong permissions, expected drwxr-xr-x, got %s", info.Mode()) 514 } 515 // new directories created with proper permissions 516 info, err = fs.Stat("/a/b/c/d") 517 if err != nil { 518 t.Fatal(err) 519 } 520 if info.Mode() != os.FileMode(os.ModeDir|0710) { 521 t.Errorf("/a/b/c/d: wrong permissions, expected drwx--x---, got %s", info.Mode()) 522 } 523 info, err = fs.Stat("/a/b/c/d/e") 524 if err != nil { 525 t.Fatal(err) 526 } 527 if info.Mode() != os.FileMode(os.ModeDir|0710) { 528 t.Errorf("/a/b/c/d/e: wrong permissions, expected drwx--x---, got %s", info.Mode()) 529 } 530 info, err = fs.Stat("/a/b/c/d/e/f") 531 if err != nil { 532 t.Fatal(err) 533 } 534 if info.Mode() != os.FileMode(os.ModeDir|0710) { 535 t.Errorf("/a/b/c/d/e/f: wrong permissions, expected drwx--x---, got %s", info.Mode()) 536 } 537 } 538 539 func TestMemFsDirMode(t *testing.T) { 540 fs := NewMemMapFs() 541 err := fs.Mkdir("/testDir1", 0644) 542 if err != nil { 543 t.Error(err) 544 } 545 err = fs.MkdirAll("/sub/testDir2", 0644) 546 if err != nil { 547 t.Error(err) 548 } 549 info, err := fs.Stat("/testDir1") 550 if err != nil { 551 t.Error(err) 552 } 553 if !info.IsDir() { 554 t.Error("should be a directory") 555 } 556 if !info.Mode().IsDir() { 557 t.Error("FileMode is not directory") 558 } 559 info, err = fs.Stat("/sub/testDir2") 560 if err != nil { 561 t.Error(err) 562 } 563 if !info.IsDir() { 564 t.Error("should be a directory") 565 } 566 if !info.Mode().IsDir() { 567 t.Error("FileMode is not directory") 568 } 569 } 570 571 func TestMemFsUnexpectedEOF(t *testing.T) { 572 t.Parallel() 573 574 fs := NewMemMapFs() 575 576 if err := WriteFile(fs, "file.txt", []byte("abc"), 0777); err != nil { 577 t.Fatal(err) 578 } 579 580 f, err := fs.Open("file.txt") 581 if err != nil { 582 t.Fatal(err) 583 } 584 defer f.Close() 585 586 // Seek beyond the end. 587 _, err = f.Seek(512, 0) 588 if err != nil { 589 t.Fatal(err) 590 } 591 592 buff := make([]byte, 256) 593 _, err = io.ReadAtLeast(f, buff, 256) 594 595 if err != io.ErrUnexpectedEOF { 596 t.Fatal("Expected ErrUnexpectedEOF") 597 } 598 } 599 600 func TestMemFsChmod(t *testing.T) { 601 t.Parallel() 602 603 fs := NewMemMapFs() 604 const file = "hello" 605 if err := fs.Mkdir(file, 0700); err != nil { 606 t.Fatal(err) 607 } 608 609 info, err := fs.Stat(file) 610 if err != nil { 611 t.Fatal(err) 612 } 613 if info.Mode().String() != "drwx------" { 614 t.Fatal("mkdir failed to create a directory: mode =", info.Mode()) 615 } 616 617 err = fs.Chmod(file, 0) 618 if err != nil { 619 t.Error("Failed to run chmod:", err) 620 } 621 622 info, err = fs.Stat(file) 623 if err != nil { 624 t.Fatal(err) 625 } 626 if info.Mode().String() != "d---------" { 627 t.Error("chmod should not change file type. New mode =", info.Mode()) 628 } 629 } 630 631 // can't use Mkdir to get around which permissions we're allowed to set 632 func TestMemFsMkdirModeIllegal(t *testing.T) { 633 t.Parallel() 634 635 fs := NewMemMapFs() 636 err := fs.Mkdir("/a", os.ModeSocket|0755) 637 if err != nil { 638 t.Fatal(err) 639 } 640 info, err := fs.Stat("/a") 641 if err != nil { 642 t.Fatal(err) 643 } 644 if info.Mode() != os.FileMode(os.ModeDir|0755) { 645 t.Fatalf("should not be able to use Mkdir to set illegal mode: %s", info.Mode().String()) 646 } 647 } 648 649 // can't use OpenFile to get around which permissions we're allowed to set 650 func TestMemFsOpenFileModeIllegal(t *testing.T) { 651 t.Parallel() 652 653 fs := NewMemMapFs() 654 file, err := fs.OpenFile("/a", os.O_CREATE, os.ModeSymlink|0644) 655 if err != nil { 656 t.Fatal(err) 657 } 658 defer file.Close() 659 info, err := fs.Stat("/a") 660 if err != nil { 661 t.Fatal(err) 662 } 663 if info.Mode() != os.FileMode(0644) { 664 t.Fatalf("should not be able to use OpenFile to set illegal mode: %s", info.Mode().String()) 665 } 666 } 667 668 // LstatIfPossible should always return false, since MemMapFs does not 669 // support symlinks. 670 func TestMemFsLstatIfPossible(t *testing.T) { 671 t.Parallel() 672 673 fs := NewMemMapFs() 674 675 // We assert that fs implements Lstater 676 fsAsserted, ok := fs.(Lstater) 677 if !ok { 678 t.Fatalf("The filesytem does not implement Lstater") 679 } 680 681 file, err := fs.OpenFile("/a.txt", os.O_CREATE, 0o644) 682 if err != nil { 683 t.Fatalf("Error when opening file: %v", err) 684 } 685 defer file.Close() 686 687 _, lstatCalled, err := fsAsserted.LstatIfPossible("/a.txt") 688 if err != nil { 689 t.Fatalf("Function returned err: %v", err) 690 } 691 if lstatCalled { 692 t.Fatalf("Function indicated lstat was called. This should never be true.") 693 } 694 }