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