github.com/c9s/go@v0.0.0-20180120015821-984e81f64e0c/src/os/os_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package os_test 6 7 import ( 8 "bytes" 9 "errors" 10 "flag" 11 "fmt" 12 "internal/testenv" 13 "io" 14 "io/ioutil" 15 . "os" 16 osexec "os/exec" 17 "path/filepath" 18 "reflect" 19 "runtime" 20 "runtime/debug" 21 "sort" 22 "strings" 23 "sync" 24 "syscall" 25 "testing" 26 "time" 27 ) 28 29 var dot = []string{ 30 "dir_unix.go", 31 "env.go", 32 "error.go", 33 "file.go", 34 "os_test.go", 35 "types.go", 36 "stat_darwin.go", 37 "stat_linux.go", 38 } 39 40 type sysDir struct { 41 name string 42 files []string 43 } 44 45 var sysdir = func() *sysDir { 46 switch runtime.GOOS { 47 case "android": 48 return &sysDir{ 49 "/system/lib", 50 []string{ 51 "libmedia.so", 52 "libpowermanager.so", 53 }, 54 } 55 case "darwin": 56 switch runtime.GOARCH { 57 case "arm", "arm64": 58 wd, err := syscall.Getwd() 59 if err != nil { 60 wd = err.Error() 61 } 62 return &sysDir{ 63 filepath.Join(wd, "..", ".."), 64 []string{ 65 "ResourceRules.plist", 66 "Info.plist", 67 }, 68 } 69 } 70 case "windows": 71 return &sysDir{ 72 Getenv("SystemRoot") + "\\system32\\drivers\\etc", 73 []string{ 74 "networks", 75 "protocol", 76 "services", 77 }, 78 } 79 case "plan9": 80 return &sysDir{ 81 "/lib/ndb", 82 []string{ 83 "common", 84 "local", 85 }, 86 } 87 } 88 return &sysDir{ 89 "/etc", 90 []string{ 91 "group", 92 "hosts", 93 "passwd", 94 }, 95 } 96 }() 97 98 func size(name string, t *testing.T) int64 { 99 file, err := Open(name) 100 if err != nil { 101 t.Fatal("open failed:", err) 102 } 103 defer file.Close() 104 var buf [100]byte 105 len := 0 106 for { 107 n, e := file.Read(buf[0:]) 108 len += n 109 if e == io.EOF { 110 break 111 } 112 if e != nil { 113 t.Fatal("read failed:", e) 114 } 115 } 116 return int64(len) 117 } 118 119 func equal(name1, name2 string) (r bool) { 120 switch runtime.GOOS { 121 case "windows": 122 r = strings.ToLower(name1) == strings.ToLower(name2) 123 default: 124 r = name1 == name2 125 } 126 return 127 } 128 129 // localTmp returns a local temporary directory not on NFS. 130 func localTmp() string { 131 switch runtime.GOOS { 132 case "android", "windows": 133 return TempDir() 134 case "darwin": 135 switch runtime.GOARCH { 136 case "arm", "arm64": 137 return TempDir() 138 } 139 } 140 return "/tmp" 141 } 142 143 func newFile(testName string, t *testing.T) (f *File) { 144 f, err := ioutil.TempFile(localTmp(), "_Go_"+testName) 145 if err != nil { 146 t.Fatalf("TempFile %s: %s", testName, err) 147 } 148 return 149 } 150 151 func newDir(testName string, t *testing.T) (name string) { 152 name, err := ioutil.TempDir(localTmp(), "_Go_"+testName) 153 if err != nil { 154 t.Fatalf("TempDir %s: %s", testName, err) 155 } 156 return 157 } 158 159 var sfdir = sysdir.name 160 var sfname = sysdir.files[0] 161 162 func TestStat(t *testing.T) { 163 path := sfdir + "/" + sfname 164 dir, err := Stat(path) 165 if err != nil { 166 t.Fatal("stat failed:", err) 167 } 168 if !equal(sfname, dir.Name()) { 169 t.Error("name should be ", sfname, "; is", dir.Name()) 170 } 171 filesize := size(path, t) 172 if dir.Size() != filesize { 173 t.Error("size should be", filesize, "; is", dir.Size()) 174 } 175 } 176 177 func TestStatError(t *testing.T) { 178 defer chtmpdir(t)() 179 180 path := "no-such-file" 181 Remove(path) // Just in case 182 183 fi, err := Stat(path) 184 if err == nil { 185 t.Fatal("got nil, want error") 186 } 187 if fi != nil { 188 t.Errorf("got %v, want nil", fi) 189 } 190 if perr, ok := err.(*PathError); !ok { 191 t.Errorf("got %T, want %T", err, perr) 192 } 193 194 testenv.MustHaveSymlink(t) 195 196 link := "symlink" 197 Remove(link) // Just in case 198 err = Symlink(path, link) 199 if err != nil { 200 t.Fatal(err) 201 } 202 defer Remove(link) 203 204 fi, err = Stat(link) 205 if err == nil { 206 t.Fatal("got nil, want error") 207 } 208 if fi != nil { 209 t.Errorf("got %v, want nil", fi) 210 } 211 if perr, ok := err.(*PathError); !ok { 212 t.Errorf("got %T, want %T", err, perr) 213 } 214 } 215 216 func TestFstat(t *testing.T) { 217 path := sfdir + "/" + sfname 218 file, err1 := Open(path) 219 if err1 != nil { 220 t.Fatal("open failed:", err1) 221 } 222 defer file.Close() 223 dir, err2 := file.Stat() 224 if err2 != nil { 225 t.Fatal("fstat failed:", err2) 226 } 227 if !equal(sfname, dir.Name()) { 228 t.Error("name should be ", sfname, "; is", dir.Name()) 229 } 230 filesize := size(path, t) 231 if dir.Size() != filesize { 232 t.Error("size should be", filesize, "; is", dir.Size()) 233 } 234 } 235 236 func TestLstat(t *testing.T) { 237 path := sfdir + "/" + sfname 238 dir, err := Lstat(path) 239 if err != nil { 240 t.Fatal("lstat failed:", err) 241 } 242 if !equal(sfname, dir.Name()) { 243 t.Error("name should be ", sfname, "; is", dir.Name()) 244 } 245 filesize := size(path, t) 246 if dir.Size() != filesize { 247 t.Error("size should be", filesize, "; is", dir.Size()) 248 } 249 } 250 251 // Read with length 0 should not return EOF. 252 func TestRead0(t *testing.T) { 253 path := sfdir + "/" + sfname 254 f, err := Open(path) 255 if err != nil { 256 t.Fatal("open failed:", err) 257 } 258 defer f.Close() 259 260 b := make([]byte, 0) 261 n, err := f.Read(b) 262 if n != 0 || err != nil { 263 t.Errorf("Read(0) = %d, %v, want 0, nil", n, err) 264 } 265 b = make([]byte, 100) 266 n, err = f.Read(b) 267 if n <= 0 || err != nil { 268 t.Errorf("Read(100) = %d, %v, want >0, nil", n, err) 269 } 270 } 271 272 // Reading a closed file should should return ErrClosed error 273 func TestReadClosed(t *testing.T) { 274 path := sfdir + "/" + sfname 275 file, err := Open(path) 276 if err != nil { 277 t.Fatal("open failed:", err) 278 } 279 file.Close() // close immediately 280 281 b := make([]byte, 100) 282 _, err = file.Read(b) 283 284 e, ok := err.(*PathError) 285 if !ok { 286 t.Fatalf("Read: %T(%v), want PathError", e, e) 287 } 288 289 if e.Err != ErrClosed { 290 t.Errorf("Read: %v, want PathError(ErrClosed)", e) 291 } 292 } 293 294 func testReaddirnames(dir string, contents []string, t *testing.T) { 295 file, err := Open(dir) 296 if err != nil { 297 t.Fatalf("open %q failed: %v", dir, err) 298 } 299 defer file.Close() 300 s, err2 := file.Readdirnames(-1) 301 if err2 != nil { 302 t.Fatalf("readdirnames %q failed: %v", dir, err2) 303 } 304 for _, m := range contents { 305 found := false 306 for _, n := range s { 307 if n == "." || n == ".." { 308 t.Errorf("got %s in directory", n) 309 } 310 if equal(m, n) { 311 if found { 312 t.Error("present twice:", m) 313 } 314 found = true 315 } 316 } 317 if !found { 318 t.Error("could not find", m) 319 } 320 } 321 } 322 323 func testReaddir(dir string, contents []string, t *testing.T) { 324 file, err := Open(dir) 325 if err != nil { 326 t.Fatalf("open %q failed: %v", dir, err) 327 } 328 defer file.Close() 329 s, err2 := file.Readdir(-1) 330 if err2 != nil { 331 t.Fatalf("readdir %q failed: %v", dir, err2) 332 } 333 for _, m := range contents { 334 found := false 335 for _, n := range s { 336 if equal(m, n.Name()) { 337 if found { 338 t.Error("present twice:", m) 339 } 340 found = true 341 } 342 } 343 if !found { 344 t.Error("could not find", m) 345 } 346 } 347 } 348 349 func TestReaddirnames(t *testing.T) { 350 testReaddirnames(".", dot, t) 351 testReaddirnames(sysdir.name, sysdir.files, t) 352 } 353 354 func TestReaddir(t *testing.T) { 355 testReaddir(".", dot, t) 356 testReaddir(sysdir.name, sysdir.files, t) 357 } 358 359 func benchmarkReaddirname(path string, b *testing.B) { 360 var nentries int 361 for i := 0; i < b.N; i++ { 362 f, err := Open(path) 363 if err != nil { 364 b.Fatalf("open %q failed: %v", path, err) 365 } 366 ns, err := f.Readdirnames(-1) 367 f.Close() 368 if err != nil { 369 b.Fatalf("readdirnames %q failed: %v", path, err) 370 } 371 nentries = len(ns) 372 } 373 b.Logf("benchmarkReaddirname %q: %d entries", path, nentries) 374 } 375 376 func benchmarkReaddir(path string, b *testing.B) { 377 var nentries int 378 for i := 0; i < b.N; i++ { 379 f, err := Open(path) 380 if err != nil { 381 b.Fatalf("open %q failed: %v", path, err) 382 } 383 fs, err := f.Readdir(-1) 384 f.Close() 385 if err != nil { 386 b.Fatalf("readdir %q failed: %v", path, err) 387 } 388 nentries = len(fs) 389 } 390 b.Logf("benchmarkReaddir %q: %d entries", path, nentries) 391 } 392 393 func BenchmarkReaddirname(b *testing.B) { 394 benchmarkReaddirname(".", b) 395 } 396 397 func BenchmarkReaddir(b *testing.B) { 398 benchmarkReaddir(".", b) 399 } 400 401 func benchmarkStat(b *testing.B, path string) { 402 b.ResetTimer() 403 for i := 0; i < b.N; i++ { 404 _, err := Stat(path) 405 if err != nil { 406 b.Fatalf("Stat(%q) failed: %v", path, err) 407 } 408 } 409 } 410 411 func benchmarkLstat(b *testing.B, path string) { 412 b.ResetTimer() 413 for i := 0; i < b.N; i++ { 414 _, err := Lstat(path) 415 if err != nil { 416 b.Fatalf("Lstat(%q) failed: %v", path, err) 417 } 418 } 419 } 420 421 func BenchmarkStatDot(b *testing.B) { 422 benchmarkStat(b, ".") 423 } 424 425 func BenchmarkStatFile(b *testing.B) { 426 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go")) 427 } 428 429 func BenchmarkStatDir(b *testing.B) { 430 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os")) 431 } 432 433 func BenchmarkLstatDot(b *testing.B) { 434 benchmarkLstat(b, ".") 435 } 436 437 func BenchmarkLstatFile(b *testing.B) { 438 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go")) 439 } 440 441 func BenchmarkLstatDir(b *testing.B) { 442 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os")) 443 } 444 445 // Read the directory one entry at a time. 446 func smallReaddirnames(file *File, length int, t *testing.T) []string { 447 names := make([]string, length) 448 count := 0 449 for { 450 d, err := file.Readdirnames(1) 451 if err == io.EOF { 452 break 453 } 454 if err != nil { 455 t.Fatalf("readdirnames %q failed: %v", file.Name(), err) 456 } 457 if len(d) == 0 { 458 t.Fatalf("readdirnames %q returned empty slice and no error", file.Name()) 459 } 460 names[count] = d[0] 461 count++ 462 } 463 return names[0:count] 464 } 465 466 // Check that reading a directory one entry at a time gives the same result 467 // as reading it all at once. 468 func TestReaddirnamesOneAtATime(t *testing.T) { 469 // big directory that doesn't change often. 470 dir := "/usr/bin" 471 switch runtime.GOOS { 472 case "android": 473 dir = "/system/bin" 474 case "darwin": 475 switch runtime.GOARCH { 476 case "arm", "arm64": 477 wd, err := Getwd() 478 if err != nil { 479 t.Fatal(err) 480 } 481 dir = wd 482 } 483 case "plan9": 484 dir = "/bin" 485 case "windows": 486 dir = Getenv("SystemRoot") + "\\system32" 487 } 488 file, err := Open(dir) 489 if err != nil { 490 t.Fatalf("open %q failed: %v", dir, err) 491 } 492 defer file.Close() 493 all, err1 := file.Readdirnames(-1) 494 if err1 != nil { 495 t.Fatalf("readdirnames %q failed: %v", dir, err1) 496 } 497 file1, err2 := Open(dir) 498 if err2 != nil { 499 t.Fatalf("open %q failed: %v", dir, err2) 500 } 501 defer file1.Close() 502 small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up 503 if len(small) < len(all) { 504 t.Fatalf("len(small) is %d, less than %d", len(small), len(all)) 505 } 506 for i, n := range all { 507 if small[i] != n { 508 t.Errorf("small read %q mismatch: %v", small[i], n) 509 } 510 } 511 } 512 513 func TestReaddirNValues(t *testing.T) { 514 if testing.Short() { 515 t.Skip("test.short; skipping") 516 } 517 dir, err := ioutil.TempDir("", "") 518 if err != nil { 519 t.Fatalf("TempDir: %v", err) 520 } 521 defer RemoveAll(dir) 522 for i := 1; i <= 105; i++ { 523 f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i))) 524 if err != nil { 525 t.Fatalf("Create: %v", err) 526 } 527 f.Write([]byte(strings.Repeat("X", i))) 528 f.Close() 529 } 530 531 var d *File 532 openDir := func() { 533 var err error 534 d, err = Open(dir) 535 if err != nil { 536 t.Fatalf("Open directory: %v", err) 537 } 538 } 539 540 readDirExpect := func(n, want int, wantErr error) { 541 fi, err := d.Readdir(n) 542 if err != wantErr { 543 t.Fatalf("Readdir of %d got error %v, want %v", n, err, wantErr) 544 } 545 if g, e := len(fi), want; g != e { 546 t.Errorf("Readdir of %d got %d files, want %d", n, g, e) 547 } 548 } 549 550 readDirNamesExpect := func(n, want int, wantErr error) { 551 fi, err := d.Readdirnames(n) 552 if err != wantErr { 553 t.Fatalf("Readdirnames of %d got error %v, want %v", n, err, wantErr) 554 } 555 if g, e := len(fi), want; g != e { 556 t.Errorf("Readdirnames of %d got %d files, want %d", n, g, e) 557 } 558 } 559 560 for _, fn := range []func(int, int, error){readDirExpect, readDirNamesExpect} { 561 // Test the slurp case 562 openDir() 563 fn(0, 105, nil) 564 fn(0, 0, nil) 565 d.Close() 566 567 // Slurp with -1 instead 568 openDir() 569 fn(-1, 105, nil) 570 fn(-2, 0, nil) 571 fn(0, 0, nil) 572 d.Close() 573 574 // Test the bounded case 575 openDir() 576 fn(1, 1, nil) 577 fn(2, 2, nil) 578 fn(105, 102, nil) // and tests buffer >100 case 579 fn(3, 0, io.EOF) 580 d.Close() 581 } 582 } 583 584 func touch(t *testing.T, name string) { 585 f, err := Create(name) 586 if err != nil { 587 t.Fatal(err) 588 } 589 if err := f.Close(); err != nil { 590 t.Fatal(err) 591 } 592 } 593 594 func TestReaddirStatFailures(t *testing.T) { 595 switch runtime.GOOS { 596 case "windows", "plan9": 597 // Windows and Plan 9 already do this correctly, 598 // but are structured with different syscalls such 599 // that they don't use Lstat, so the hook below for 600 // testing it wouldn't work. 601 t.Skipf("skipping test on %v", runtime.GOOS) 602 } 603 dir, err := ioutil.TempDir("", "") 604 if err != nil { 605 t.Fatalf("TempDir: %v", err) 606 } 607 defer RemoveAll(dir) 608 touch(t, filepath.Join(dir, "good1")) 609 touch(t, filepath.Join(dir, "x")) // will disappear or have an error 610 touch(t, filepath.Join(dir, "good2")) 611 defer func() { 612 *LstatP = Lstat 613 }() 614 var xerr error // error to return for x 615 *LstatP = func(path string) (FileInfo, error) { 616 if xerr != nil && strings.HasSuffix(path, "x") { 617 return nil, xerr 618 } 619 return Lstat(path) 620 } 621 readDir := func() ([]FileInfo, error) { 622 d, err := Open(dir) 623 if err != nil { 624 t.Fatal(err) 625 } 626 defer d.Close() 627 return d.Readdir(-1) 628 } 629 mustReadDir := func(testName string) []FileInfo { 630 fis, err := readDir() 631 if err != nil { 632 t.Fatalf("%s: Readdir: %v", testName, err) 633 } 634 return fis 635 } 636 names := func(fis []FileInfo) []string { 637 s := make([]string, len(fis)) 638 for i, fi := range fis { 639 s[i] = fi.Name() 640 } 641 sort.Strings(s) 642 return s 643 } 644 645 if got, want := names(mustReadDir("initial readdir")), 646 []string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) { 647 t.Errorf("initial readdir got %q; want %q", got, want) 648 } 649 650 xerr = ErrNotExist 651 if got, want := names(mustReadDir("with x disappearing")), 652 []string{"good1", "good2"}; !reflect.DeepEqual(got, want) { 653 t.Errorf("with x disappearing, got %q; want %q", got, want) 654 } 655 656 xerr = errors.New("some real error") 657 if _, err := readDir(); err != xerr { 658 t.Errorf("with a non-ErrNotExist error, got error %v; want %v", err, xerr) 659 } 660 } 661 662 // Readdir on a regular file should fail. 663 func TestReaddirOfFile(t *testing.T) { 664 f, err := ioutil.TempFile("", "_Go_ReaddirOfFile") 665 if err != nil { 666 t.Fatal(err) 667 } 668 defer Remove(f.Name()) 669 f.Write([]byte("foo")) 670 f.Close() 671 reg, err := Open(f.Name()) 672 if err != nil { 673 t.Fatal(err) 674 } 675 defer reg.Close() 676 677 names, err := reg.Readdirnames(-1) 678 if err == nil { 679 t.Error("Readdirnames succeeded; want non-nil error") 680 } 681 if len(names) > 0 { 682 t.Errorf("unexpected dir names in regular file: %q", names) 683 } 684 } 685 686 func TestHardLink(t *testing.T) { 687 testenv.MustHaveLink(t) 688 689 defer chtmpdir(t)() 690 from, to := "hardlinktestfrom", "hardlinktestto" 691 Remove(from) // Just in case. 692 file, err := Create(to) 693 if err != nil { 694 t.Fatalf("open %q failed: %v", to, err) 695 } 696 defer Remove(to) 697 if err = file.Close(); err != nil { 698 t.Errorf("close %q failed: %v", to, err) 699 } 700 err = Link(to, from) 701 if err != nil { 702 t.Fatalf("link %q, %q failed: %v", to, from, err) 703 } 704 705 none := "hardlinktestnone" 706 err = Link(none, none) 707 // Check the returned error is well-formed. 708 if lerr, ok := err.(*LinkError); !ok || lerr.Error() == "" { 709 t.Errorf("link %q, %q failed to return a valid error", none, none) 710 } 711 712 defer Remove(from) 713 tostat, err := Stat(to) 714 if err != nil { 715 t.Fatalf("stat %q failed: %v", to, err) 716 } 717 fromstat, err := Stat(from) 718 if err != nil { 719 t.Fatalf("stat %q failed: %v", from, err) 720 } 721 if !SameFile(tostat, fromstat) { 722 t.Errorf("link %q, %q did not create hard link", to, from) 723 } 724 // We should not be able to perform the same Link() a second time 725 err = Link(to, from) 726 switch err := err.(type) { 727 case *LinkError: 728 if err.Op != "link" { 729 t.Errorf("Link(%q, %q) err.Op = %q; want %q", to, from, err.Op, "link") 730 } 731 if err.Old != to { 732 t.Errorf("Link(%q, %q) err.Old = %q; want %q", to, from, err.Old, to) 733 } 734 if err.New != from { 735 t.Errorf("Link(%q, %q) err.New = %q; want %q", to, from, err.New, from) 736 } 737 if !IsExist(err.Err) { 738 t.Errorf("Link(%q, %q) err.Err = %q; want %q", to, from, err.Err, "file exists error") 739 } 740 case nil: 741 t.Errorf("link %q, %q: expected error, got nil", from, to) 742 default: 743 t.Errorf("link %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) 744 } 745 } 746 747 // chtmpdir changes the working directory to a new temporary directory and 748 // provides a cleanup function. Used when PWD is read-only. 749 func chtmpdir(t *testing.T) func() { 750 if runtime.GOOS != "darwin" || (runtime.GOARCH != "arm" && runtime.GOARCH != "arm64") { 751 return func() {} // only needed on darwin/arm{,64} 752 } 753 oldwd, err := Getwd() 754 if err != nil { 755 t.Fatalf("chtmpdir: %v", err) 756 } 757 d, err := ioutil.TempDir("", "test") 758 if err != nil { 759 t.Fatalf("chtmpdir: %v", err) 760 } 761 if err := Chdir(d); err != nil { 762 t.Fatalf("chtmpdir: %v", err) 763 } 764 return func() { 765 if err := Chdir(oldwd); err != nil { 766 t.Fatalf("chtmpdir: %v", err) 767 } 768 RemoveAll(d) 769 } 770 } 771 772 func TestSymlink(t *testing.T) { 773 testenv.MustHaveSymlink(t) 774 775 defer chtmpdir(t)() 776 from, to := "symlinktestfrom", "symlinktestto" 777 Remove(from) // Just in case. 778 file, err := Create(to) 779 if err != nil { 780 t.Fatalf("Create(%q) failed: %v", to, err) 781 } 782 defer Remove(to) 783 if err = file.Close(); err != nil { 784 t.Errorf("Close(%q) failed: %v", to, err) 785 } 786 err = Symlink(to, from) 787 if err != nil { 788 t.Fatalf("Symlink(%q, %q) failed: %v", to, from, err) 789 } 790 defer Remove(from) 791 tostat, err := Lstat(to) 792 if err != nil { 793 t.Fatalf("Lstat(%q) failed: %v", to, err) 794 } 795 if tostat.Mode()&ModeSymlink != 0 { 796 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = %v, want 0", to, tostat.Mode()&ModeSymlink) 797 } 798 fromstat, err := Stat(from) 799 if err != nil { 800 t.Fatalf("Stat(%q) failed: %v", from, err) 801 } 802 if !SameFile(tostat, fromstat) { 803 t.Errorf("Symlink(%q, %q) did not create symlink", to, from) 804 } 805 fromstat, err = Lstat(from) 806 if err != nil { 807 t.Fatalf("Lstat(%q) failed: %v", from, err) 808 } 809 if fromstat.Mode()&ModeSymlink == 0 { 810 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = 0, want %v", from, ModeSymlink) 811 } 812 fromstat, err = Stat(from) 813 if err != nil { 814 t.Fatalf("Stat(%q) failed: %v", from, err) 815 } 816 if fromstat.Name() != from { 817 t.Errorf("Stat(%q).Name() = %q, want %q", from, fromstat.Name(), from) 818 } 819 if fromstat.Mode()&ModeSymlink != 0 { 820 t.Fatalf("Stat(%q).Mode()&ModeSymlink = %v, want 0", from, fromstat.Mode()&ModeSymlink) 821 } 822 s, err := Readlink(from) 823 if err != nil { 824 t.Fatalf("Readlink(%q) failed: %v", from, err) 825 } 826 if s != to { 827 t.Fatalf("Readlink(%q) = %q, want %q", from, s, to) 828 } 829 file, err = Open(from) 830 if err != nil { 831 t.Fatalf("Open(%q) failed: %v", from, err) 832 } 833 file.Close() 834 } 835 836 func TestLongSymlink(t *testing.T) { 837 testenv.MustHaveSymlink(t) 838 839 defer chtmpdir(t)() 840 s := "0123456789abcdef" 841 // Long, but not too long: a common limit is 255. 842 s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s 843 from := "longsymlinktestfrom" 844 Remove(from) // Just in case. 845 err := Symlink(s, from) 846 if err != nil { 847 t.Fatalf("symlink %q, %q failed: %v", s, from, err) 848 } 849 defer Remove(from) 850 r, err := Readlink(from) 851 if err != nil { 852 t.Fatalf("readlink %q failed: %v", from, err) 853 } 854 if r != s { 855 t.Fatalf("after symlink %q != %q", r, s) 856 } 857 } 858 859 func TestRename(t *testing.T) { 860 defer chtmpdir(t)() 861 from, to := "renamefrom", "renameto" 862 // Ensure we are not testing the overwrite case here. 863 Remove(from) 864 Remove(to) 865 866 file, err := Create(from) 867 if err != nil { 868 t.Fatalf("open %q failed: %v", from, err) 869 } 870 if err = file.Close(); err != nil { 871 t.Errorf("close %q failed: %v", from, err) 872 } 873 err = Rename(from, to) 874 if err != nil { 875 t.Fatalf("rename %q, %q failed: %v", to, from, err) 876 } 877 defer Remove(to) 878 _, err = Stat(to) 879 if err != nil { 880 t.Errorf("stat %q failed: %v", to, err) 881 } 882 } 883 884 func TestRenameOverwriteDest(t *testing.T) { 885 defer chtmpdir(t)() 886 from, to := "renamefrom", "renameto" 887 // Just in case. 888 Remove(from) 889 Remove(to) 890 891 toData := []byte("to") 892 fromData := []byte("from") 893 894 err := ioutil.WriteFile(to, toData, 0777) 895 if err != nil { 896 t.Fatalf("write file %q failed: %v", to, err) 897 } 898 899 err = ioutil.WriteFile(from, fromData, 0777) 900 if err != nil { 901 t.Fatalf("write file %q failed: %v", from, err) 902 } 903 err = Rename(from, to) 904 if err != nil { 905 t.Fatalf("rename %q, %q failed: %v", to, from, err) 906 } 907 defer Remove(to) 908 909 _, err = Stat(from) 910 if err == nil { 911 t.Errorf("from file %q still exists", from) 912 } 913 if err != nil && !IsNotExist(err) { 914 t.Fatalf("stat from: %v", err) 915 } 916 toFi, err := Stat(to) 917 if err != nil { 918 t.Fatalf("stat %q failed: %v", to, err) 919 } 920 if toFi.Size() != int64(len(fromData)) { 921 t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData)) 922 } 923 } 924 925 func TestRenameFailed(t *testing.T) { 926 defer chtmpdir(t)() 927 from, to := "renamefrom", "renameto" 928 // Ensure we are not testing the overwrite case here. 929 Remove(from) 930 Remove(to) 931 932 err := Rename(from, to) 933 switch err := err.(type) { 934 case *LinkError: 935 if err.Op != "rename" { 936 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op) 937 } 938 if err.Old != from { 939 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old) 940 } 941 if err.New != to { 942 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New) 943 } 944 case nil: 945 t.Errorf("rename %q, %q: expected error, got nil", from, to) 946 947 // cleanup whatever was placed in "renameto" 948 Remove(to) 949 default: 950 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) 951 } 952 } 953 954 func TestRenameNotExisting(t *testing.T) { 955 defer chtmpdir(t)() 956 from, to := "doesnt-exist", "dest" 957 958 Mkdir(to, 0777) 959 defer Remove(to) 960 961 if err := Rename(from, to); !IsNotExist(err) { 962 t.Errorf("Rename(%q, %q) = %v; want an IsNotExist error", from, to, err) 963 } 964 } 965 966 func TestRenameToDirFailed(t *testing.T) { 967 defer chtmpdir(t)() 968 from, to := "renamefrom", "renameto" 969 970 Remove(from) 971 Remove(to) 972 Mkdir(from, 0777) 973 Mkdir(to, 0777) 974 defer Remove(from) 975 defer Remove(to) 976 977 err := Rename(from, to) 978 switch err := err.(type) { 979 case *LinkError: 980 if err.Op != "rename" { 981 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op) 982 } 983 if err.Old != from { 984 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old) 985 } 986 if err.New != to { 987 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New) 988 } 989 case nil: 990 t.Errorf("rename %q, %q: expected error, got nil", from, to) 991 992 // cleanup whatever was placed in "renameto" 993 Remove(to) 994 default: 995 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) 996 } 997 } 998 999 func exec(t *testing.T, dir, cmd string, args []string, expect string) { 1000 r, w, err := Pipe() 1001 if err != nil { 1002 t.Fatalf("Pipe: %v", err) 1003 } 1004 defer r.Close() 1005 attr := &ProcAttr{Dir: dir, Files: []*File{nil, w, Stderr}} 1006 p, err := StartProcess(cmd, args, attr) 1007 if err != nil { 1008 t.Fatalf("StartProcess: %v", err) 1009 } 1010 w.Close() 1011 1012 var b bytes.Buffer 1013 io.Copy(&b, r) 1014 output := b.String() 1015 1016 fi1, _ := Stat(strings.TrimSpace(output)) 1017 fi2, _ := Stat(expect) 1018 if !SameFile(fi1, fi2) { 1019 t.Errorf("exec %q returned %q wanted %q", 1020 strings.Join(append([]string{cmd}, args...), " "), output, expect) 1021 } 1022 p.Wait() 1023 } 1024 1025 func TestStartProcess(t *testing.T) { 1026 testenv.MustHaveExec(t) 1027 1028 var dir, cmd string 1029 var args []string 1030 switch runtime.GOOS { 1031 case "android": 1032 t.Skip("android doesn't have /bin/pwd") 1033 case "windows": 1034 cmd = Getenv("COMSPEC") 1035 dir = Getenv("SystemRoot") 1036 args = []string{"/c", "cd"} 1037 default: 1038 var err error 1039 cmd, err = osexec.LookPath("pwd") 1040 if err != nil { 1041 t.Fatalf("Can't find pwd: %v", err) 1042 } 1043 dir = "/" 1044 args = []string{} 1045 t.Logf("Testing with %v", cmd) 1046 } 1047 cmddir, cmdbase := filepath.Split(cmd) 1048 args = append([]string{cmdbase}, args...) 1049 // Test absolute executable path. 1050 exec(t, dir, cmd, args, dir) 1051 // Test relative executable path. 1052 exec(t, cmddir, cmdbase, args, cmddir) 1053 } 1054 1055 func checkMode(t *testing.T, path string, mode FileMode) { 1056 dir, err := Stat(path) 1057 if err != nil { 1058 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err) 1059 } 1060 if dir.Mode()&0777 != mode { 1061 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode) 1062 } 1063 } 1064 1065 func TestChmod(t *testing.T) { 1066 // Chmod is not supported under windows. 1067 if runtime.GOOS == "windows" { 1068 return 1069 } 1070 f := newFile("TestChmod", t) 1071 defer Remove(f.Name()) 1072 defer f.Close() 1073 1074 if err := Chmod(f.Name(), 0456); err != nil { 1075 t.Fatalf("chmod %s 0456: %s", f.Name(), err) 1076 } 1077 checkMode(t, f.Name(), 0456) 1078 1079 if err := f.Chmod(0123); err != nil { 1080 t.Fatalf("chmod %s 0123: %s", f.Name(), err) 1081 } 1082 checkMode(t, f.Name(), 0123) 1083 } 1084 1085 func checkSize(t *testing.T, f *File, size int64) { 1086 dir, err := f.Stat() 1087 if err != nil { 1088 t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err) 1089 } 1090 if dir.Size() != size { 1091 t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size) 1092 } 1093 } 1094 1095 func TestFTruncate(t *testing.T) { 1096 f := newFile("TestFTruncate", t) 1097 defer Remove(f.Name()) 1098 defer f.Close() 1099 1100 checkSize(t, f, 0) 1101 f.Write([]byte("hello, world\n")) 1102 checkSize(t, f, 13) 1103 f.Truncate(10) 1104 checkSize(t, f, 10) 1105 f.Truncate(1024) 1106 checkSize(t, f, 1024) 1107 f.Truncate(0) 1108 checkSize(t, f, 0) 1109 _, err := f.Write([]byte("surprise!")) 1110 if err == nil { 1111 checkSize(t, f, 13+9) // wrote at offset past where hello, world was. 1112 } 1113 } 1114 1115 func TestTruncate(t *testing.T) { 1116 f := newFile("TestTruncate", t) 1117 defer Remove(f.Name()) 1118 defer f.Close() 1119 1120 checkSize(t, f, 0) 1121 f.Write([]byte("hello, world\n")) 1122 checkSize(t, f, 13) 1123 Truncate(f.Name(), 10) 1124 checkSize(t, f, 10) 1125 Truncate(f.Name(), 1024) 1126 checkSize(t, f, 1024) 1127 Truncate(f.Name(), 0) 1128 checkSize(t, f, 0) 1129 _, err := f.Write([]byte("surprise!")) 1130 if err == nil { 1131 checkSize(t, f, 13+9) // wrote at offset past where hello, world was. 1132 } 1133 } 1134 1135 // Use TempDir (via newFile) to make sure we're on a local file system, 1136 // so that timings are not distorted by latency and caching. 1137 // On NFS, timings can be off due to caching of meta-data on 1138 // NFS servers (Issue 848). 1139 func TestChtimes(t *testing.T) { 1140 f := newFile("TestChtimes", t) 1141 defer Remove(f.Name()) 1142 1143 f.Write([]byte("hello, world\n")) 1144 f.Close() 1145 1146 testChtimes(t, f.Name()) 1147 } 1148 1149 // Use TempDir (via newDir) to make sure we're on a local file system, 1150 // so that timings are not distorted by latency and caching. 1151 // On NFS, timings can be off due to caching of meta-data on 1152 // NFS servers (Issue 848). 1153 func TestChtimesDir(t *testing.T) { 1154 name := newDir("TestChtimes", t) 1155 defer RemoveAll(name) 1156 1157 testChtimes(t, name) 1158 } 1159 1160 func testChtimes(t *testing.T, name string) { 1161 st, err := Stat(name) 1162 if err != nil { 1163 t.Fatalf("Stat %s: %s", name, err) 1164 } 1165 preStat := st 1166 1167 // Move access and modification time back a second 1168 at := Atime(preStat) 1169 mt := preStat.ModTime() 1170 err = Chtimes(name, at.Add(-time.Second), mt.Add(-time.Second)) 1171 if err != nil { 1172 t.Fatalf("Chtimes %s: %s", name, err) 1173 } 1174 1175 st, err = Stat(name) 1176 if err != nil { 1177 t.Fatalf("second Stat %s: %s", name, err) 1178 } 1179 postStat := st 1180 1181 pat := Atime(postStat) 1182 pmt := postStat.ModTime() 1183 if !pat.Before(at) { 1184 switch runtime.GOOS { 1185 case "plan9", "nacl": 1186 // Ignore. 1187 // Plan 9, NaCl: 1188 // Mtime is the time of the last change of 1189 // content. Similarly, atime is set whenever 1190 // the contents are accessed; also, it is set 1191 // whenever mtime is set. 1192 case "netbsd": 1193 mounts, _ := ioutil.ReadFile("/proc/mounts") 1194 if strings.Contains(string(mounts), "noatime") { 1195 t.Logf("AccessTime didn't go backwards, but see a filesystem mounted noatime; ignoring. Issue 19293.") 1196 } else { 1197 t.Logf("AccessTime didn't go backwards; was=%v, after=%v (Ignoring on NetBSD, assuming noatime, Issue 19293)", at, pat) 1198 } 1199 default: 1200 t.Errorf("AccessTime didn't go backwards; was=%v, after=%v", at, pat) 1201 } 1202 } 1203 1204 if !pmt.Before(mt) { 1205 t.Errorf("ModTime didn't go backwards; was=%v, after=%v", mt, pmt) 1206 } 1207 } 1208 1209 func TestChdirAndGetwd(t *testing.T) { 1210 // TODO(brainman): file.Chdir() is not implemented on windows. 1211 if runtime.GOOS == "windows" { 1212 return 1213 } 1214 fd, err := Open(".") 1215 if err != nil { 1216 t.Fatalf("Open .: %s", err) 1217 } 1218 // These are chosen carefully not to be symlinks on a Mac 1219 // (unlike, say, /var, /etc), except /tmp, which we handle below. 1220 dirs := []string{"/", "/usr/bin", "/tmp"} 1221 // /usr/bin does not usually exist on Plan 9 or Android. 1222 switch runtime.GOOS { 1223 case "android": 1224 dirs = []string{"/", "/system/bin"} 1225 case "plan9": 1226 dirs = []string{"/", "/usr"} 1227 case "darwin": 1228 switch runtime.GOARCH { 1229 case "arm", "arm64": 1230 d1, err := ioutil.TempDir("", "d1") 1231 if err != nil { 1232 t.Fatalf("TempDir: %v", err) 1233 } 1234 d2, err := ioutil.TempDir("", "d2") 1235 if err != nil { 1236 t.Fatalf("TempDir: %v", err) 1237 } 1238 dirs = []string{d1, d2} 1239 } 1240 } 1241 oldwd := Getenv("PWD") 1242 for mode := 0; mode < 2; mode++ { 1243 for _, d := range dirs { 1244 if mode == 0 { 1245 err = Chdir(d) 1246 } else { 1247 fd1, err1 := Open(d) 1248 if err1 != nil { 1249 t.Errorf("Open %s: %s", d, err1) 1250 continue 1251 } 1252 err = fd1.Chdir() 1253 fd1.Close() 1254 } 1255 if d == "/tmp" { 1256 Setenv("PWD", "/tmp") 1257 } 1258 pwd, err1 := Getwd() 1259 Setenv("PWD", oldwd) 1260 err2 := fd.Chdir() 1261 if err2 != nil { 1262 // We changed the current directory and cannot go back. 1263 // Don't let the tests continue; they'll scribble 1264 // all over some other directory. 1265 fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2) 1266 Exit(1) 1267 } 1268 if err != nil { 1269 fd.Close() 1270 t.Fatalf("Chdir %s: %s", d, err) 1271 } 1272 if err1 != nil { 1273 fd.Close() 1274 t.Fatalf("Getwd in %s: %s", d, err1) 1275 } 1276 if pwd != d { 1277 fd.Close() 1278 t.Fatalf("Getwd returned %q want %q", pwd, d) 1279 } 1280 } 1281 } 1282 fd.Close() 1283 } 1284 1285 // Test that Chdir+Getwd is program-wide. 1286 func TestProgWideChdir(t *testing.T) { 1287 const N = 10 1288 c := make(chan bool) 1289 cpwd := make(chan string) 1290 for i := 0; i < N; i++ { 1291 go func(i int) { 1292 // Lock half the goroutines in their own operating system 1293 // thread to exercise more scheduler possibilities. 1294 if i%2 == 1 { 1295 // On Plan 9, after calling LockOSThread, the goroutines 1296 // run on different processes which don't share the working 1297 // directory. This used to be an issue because Go expects 1298 // the working directory to be program-wide. 1299 // See issue 9428. 1300 runtime.LockOSThread() 1301 } 1302 <-c 1303 pwd, err := Getwd() 1304 if err != nil { 1305 t.Errorf("Getwd on goroutine %d: %v", i, err) 1306 return 1307 } 1308 cpwd <- pwd 1309 }(i) 1310 } 1311 oldwd, err := Getwd() 1312 if err != nil { 1313 t.Fatalf("Getwd: %v", err) 1314 } 1315 d, err := ioutil.TempDir("", "test") 1316 if err != nil { 1317 t.Fatalf("TempDir: %v", err) 1318 } 1319 defer func() { 1320 if err := Chdir(oldwd); err != nil { 1321 t.Fatalf("Chdir: %v", err) 1322 } 1323 RemoveAll(d) 1324 }() 1325 if err := Chdir(d); err != nil { 1326 t.Fatalf("Chdir: %v", err) 1327 } 1328 // OS X sets TMPDIR to a symbolic link. 1329 // So we resolve our working directory again before the test. 1330 d, err = Getwd() 1331 if err != nil { 1332 t.Fatalf("Getwd: %v", err) 1333 } 1334 close(c) 1335 for i := 0; i < N; i++ { 1336 pwd := <-cpwd 1337 if pwd != d { 1338 t.Errorf("Getwd returned %q; want %q", pwd, d) 1339 } 1340 } 1341 } 1342 1343 func TestSeek(t *testing.T) { 1344 f := newFile("TestSeek", t) 1345 defer Remove(f.Name()) 1346 defer f.Close() 1347 1348 const data = "hello, world\n" 1349 io.WriteString(f, data) 1350 1351 type test struct { 1352 in int64 1353 whence int 1354 out int64 1355 } 1356 var tests = []test{ 1357 {0, io.SeekCurrent, int64(len(data))}, 1358 {0, io.SeekStart, 0}, 1359 {5, io.SeekStart, 5}, 1360 {0, io.SeekEnd, int64(len(data))}, 1361 {0, io.SeekStart, 0}, 1362 {-1, io.SeekEnd, int64(len(data)) - 1}, 1363 {1 << 33, io.SeekStart, 1 << 33}, 1364 {1 << 33, io.SeekEnd, 1<<33 + int64(len(data))}, 1365 1366 // Issue 21681, Windows 4G-1, etc: 1367 {1<<32 - 1, io.SeekStart, 1<<32 - 1}, 1368 {0, io.SeekCurrent, 1<<32 - 1}, 1369 {2<<32 - 1, io.SeekStart, 2<<32 - 1}, 1370 {0, io.SeekCurrent, 2<<32 - 1}, 1371 } 1372 for i, tt := range tests { 1373 if runtime.GOOS == "nacl" && tt.out > 1<<30 { 1374 t.Logf("skipping test case #%d on nacl; https://golang.org/issue/21728", i) 1375 continue 1376 } 1377 off, err := f.Seek(tt.in, tt.whence) 1378 if off != tt.out || err != nil { 1379 if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 && runtime.GOOS == "linux" { 1380 mounts, _ := ioutil.ReadFile("/proc/mounts") 1381 if strings.Contains(string(mounts), "reiserfs") { 1382 // Reiserfs rejects the big seeks. 1383 t.Skipf("skipping test known to fail on reiserfs; https://golang.org/issue/91") 1384 } 1385 } 1386 t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out) 1387 } 1388 } 1389 } 1390 1391 func TestSeekError(t *testing.T) { 1392 switch runtime.GOOS { 1393 case "plan9", "nacl": 1394 t.Skipf("skipping test on %v", runtime.GOOS) 1395 } 1396 1397 r, w, err := Pipe() 1398 if err != nil { 1399 t.Fatal(err) 1400 } 1401 _, err = r.Seek(0, 0) 1402 if err == nil { 1403 t.Fatal("Seek on pipe should fail") 1404 } 1405 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE { 1406 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err) 1407 } 1408 _, err = w.Seek(0, 0) 1409 if err == nil { 1410 t.Fatal("Seek on pipe should fail") 1411 } 1412 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE { 1413 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err) 1414 } 1415 } 1416 1417 type openErrorTest struct { 1418 path string 1419 mode int 1420 error error 1421 } 1422 1423 var openErrorTests = []openErrorTest{ 1424 { 1425 sfdir + "/no-such-file", 1426 O_RDONLY, 1427 syscall.ENOENT, 1428 }, 1429 { 1430 sfdir, 1431 O_WRONLY, 1432 syscall.EISDIR, 1433 }, 1434 { 1435 sfdir + "/" + sfname + "/no-such-file", 1436 O_WRONLY, 1437 syscall.ENOTDIR, 1438 }, 1439 } 1440 1441 func TestOpenError(t *testing.T) { 1442 for _, tt := range openErrorTests { 1443 f, err := OpenFile(tt.path, tt.mode, 0) 1444 if err == nil { 1445 t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode) 1446 f.Close() 1447 continue 1448 } 1449 perr, ok := err.(*PathError) 1450 if !ok { 1451 t.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt.path, tt.mode, err) 1452 } 1453 if perr.Err != tt.error { 1454 if runtime.GOOS == "plan9" { 1455 syscallErrStr := perr.Err.Error() 1456 expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1) 1457 if !strings.HasSuffix(syscallErrStr, expectedErrStr) { 1458 // Some Plan 9 file servers incorrectly return 1459 // EACCES rather than EISDIR when a directory is 1460 // opened for write. 1461 if tt.error == syscall.EISDIR && strings.HasSuffix(syscallErrStr, syscall.EACCES.Error()) { 1462 continue 1463 } 1464 t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr) 1465 } 1466 continue 1467 } 1468 if runtime.GOOS == "dragonfly" { 1469 // DragonFly incorrectly returns EACCES rather 1470 // EISDIR when a directory is opened for write. 1471 if tt.error == syscall.EISDIR && perr.Err == syscall.EACCES { 1472 continue 1473 } 1474 } 1475 t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Err.Error(), tt.error.Error()) 1476 } 1477 } 1478 } 1479 1480 func TestOpenNoName(t *testing.T) { 1481 f, err := Open("") 1482 if err == nil { 1483 t.Fatal(`Open("") succeeded`) 1484 f.Close() 1485 } 1486 } 1487 1488 func runBinHostname(t *testing.T) string { 1489 // Run /bin/hostname and collect output. 1490 r, w, err := Pipe() 1491 if err != nil { 1492 t.Fatal(err) 1493 } 1494 defer r.Close() 1495 const path = "/bin/hostname" 1496 p, err := StartProcess(path, []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}}) 1497 if err != nil { 1498 if _, err := Stat(path); IsNotExist(err) { 1499 t.Skipf("skipping test; test requires %s but it does not exist", path) 1500 } 1501 t.Fatal(err) 1502 } 1503 w.Close() 1504 1505 var b bytes.Buffer 1506 io.Copy(&b, r) 1507 _, err = p.Wait() 1508 if err != nil { 1509 t.Fatalf("run hostname Wait: %v", err) 1510 } 1511 err = p.Kill() 1512 if err == nil { 1513 t.Errorf("expected an error from Kill running 'hostname'") 1514 } 1515 output := b.String() 1516 if n := len(output); n > 0 && output[n-1] == '\n' { 1517 output = output[0 : n-1] 1518 } 1519 if output == "" { 1520 t.Fatalf("/bin/hostname produced no output") 1521 } 1522 1523 return output 1524 } 1525 1526 func testWindowsHostname(t *testing.T) { 1527 hostname, err := Hostname() 1528 if err != nil { 1529 t.Fatal(err) 1530 } 1531 cmd := osexec.Command("hostname") 1532 out, err := cmd.CombinedOutput() 1533 if err != nil { 1534 t.Fatalf("Failed to execute hostname command: %v %s", err, out) 1535 } 1536 want := strings.Trim(string(out), "\r\n") 1537 if hostname != want { 1538 t.Fatalf("Hostname() = %q, want %q", hostname, want) 1539 } 1540 } 1541 1542 func TestHostname(t *testing.T) { 1543 // There is no other way to fetch hostname on windows, but via winapi. 1544 // On Plan 9 it can be taken from #c/sysname as Hostname() does. 1545 switch runtime.GOOS { 1546 case "android", "plan9": 1547 t.Skipf("%s doesn't have /bin/hostname", runtime.GOOS) 1548 case "windows": 1549 testWindowsHostname(t) 1550 return 1551 } 1552 1553 testenv.MustHaveExec(t) 1554 1555 // Check internal Hostname() against the output of /bin/hostname. 1556 // Allow that the internal Hostname returns a Fully Qualified Domain Name 1557 // and the /bin/hostname only returns the first component 1558 hostname, err := Hostname() 1559 if err != nil { 1560 t.Fatalf("%v", err) 1561 } 1562 want := runBinHostname(t) 1563 if hostname != want { 1564 i := strings.Index(hostname, ".") 1565 if i < 0 || hostname[0:i] != want { 1566 t.Errorf("Hostname() = %q, want %q", hostname, want) 1567 } 1568 } 1569 } 1570 1571 func TestReadAt(t *testing.T) { 1572 f := newFile("TestReadAt", t) 1573 defer Remove(f.Name()) 1574 defer f.Close() 1575 1576 const data = "hello, world\n" 1577 io.WriteString(f, data) 1578 1579 b := make([]byte, 5) 1580 n, err := f.ReadAt(b, 7) 1581 if err != nil || n != len(b) { 1582 t.Fatalf("ReadAt 7: %d, %v", n, err) 1583 } 1584 if string(b) != "world" { 1585 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world") 1586 } 1587 } 1588 1589 // Verify that ReadAt doesn't affect seek offset. 1590 // In the Plan 9 kernel, there used to be a bug in the implementation of 1591 // the pread syscall, where the channel offset was erroneously updated after 1592 // calling pread on a file. 1593 func TestReadAtOffset(t *testing.T) { 1594 f := newFile("TestReadAtOffset", t) 1595 defer Remove(f.Name()) 1596 defer f.Close() 1597 1598 const data = "hello, world\n" 1599 io.WriteString(f, data) 1600 1601 f.Seek(0, 0) 1602 b := make([]byte, 5) 1603 1604 n, err := f.ReadAt(b, 7) 1605 if err != nil || n != len(b) { 1606 t.Fatalf("ReadAt 7: %d, %v", n, err) 1607 } 1608 if string(b) != "world" { 1609 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world") 1610 } 1611 1612 n, err = f.Read(b) 1613 if err != nil || n != len(b) { 1614 t.Fatalf("Read: %d, %v", n, err) 1615 } 1616 if string(b) != "hello" { 1617 t.Fatalf("Read: have %q want %q", string(b), "hello") 1618 } 1619 } 1620 1621 // Verify that ReadAt doesn't allow negative offset. 1622 func TestReadAtNegativeOffset(t *testing.T) { 1623 f := newFile("TestReadAtNegativeOffset", t) 1624 defer Remove(f.Name()) 1625 defer f.Close() 1626 1627 const data = "hello, world\n" 1628 io.WriteString(f, data) 1629 1630 f.Seek(0, 0) 1631 b := make([]byte, 5) 1632 1633 n, err := f.ReadAt(b, -10) 1634 1635 const wantsub = "negative offset" 1636 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 { 1637 t.Errorf("ReadAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub) 1638 } 1639 } 1640 1641 func TestWriteAt(t *testing.T) { 1642 f := newFile("TestWriteAt", t) 1643 defer Remove(f.Name()) 1644 defer f.Close() 1645 1646 const data = "hello, world\n" 1647 io.WriteString(f, data) 1648 1649 n, err := f.WriteAt([]byte("WORLD"), 7) 1650 if err != nil || n != 5 { 1651 t.Fatalf("WriteAt 7: %d, %v", n, err) 1652 } 1653 1654 b, err := ioutil.ReadFile(f.Name()) 1655 if err != nil { 1656 t.Fatalf("ReadFile %s: %v", f.Name(), err) 1657 } 1658 if string(b) != "hello, WORLD\n" { 1659 t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n") 1660 } 1661 } 1662 1663 // Verify that WriteAt doesn't allow negative offset. 1664 func TestWriteAtNegativeOffset(t *testing.T) { 1665 f := newFile("TestWriteAtNegativeOffset", t) 1666 defer Remove(f.Name()) 1667 defer f.Close() 1668 1669 n, err := f.WriteAt([]byte("WORLD"), -10) 1670 1671 const wantsub = "negative offset" 1672 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 { 1673 t.Errorf("WriteAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub) 1674 } 1675 } 1676 1677 func writeFile(t *testing.T, fname string, flag int, text string) string { 1678 f, err := OpenFile(fname, flag, 0666) 1679 if err != nil { 1680 t.Fatalf("Open: %v", err) 1681 } 1682 n, err := io.WriteString(f, text) 1683 if err != nil { 1684 t.Fatalf("WriteString: %d, %v", n, err) 1685 } 1686 f.Close() 1687 data, err := ioutil.ReadFile(fname) 1688 if err != nil { 1689 t.Fatalf("ReadFile: %v", err) 1690 } 1691 return string(data) 1692 } 1693 1694 func TestAppend(t *testing.T) { 1695 defer chtmpdir(t)() 1696 const f = "append.txt" 1697 defer Remove(f) 1698 s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") 1699 if s != "new" { 1700 t.Fatalf("writeFile: have %q want %q", s, "new") 1701 } 1702 s = writeFile(t, f, O_APPEND|O_RDWR, "|append") 1703 if s != "new|append" { 1704 t.Fatalf("writeFile: have %q want %q", s, "new|append") 1705 } 1706 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "|append") 1707 if s != "new|append|append" { 1708 t.Fatalf("writeFile: have %q want %q", s, "new|append|append") 1709 } 1710 err := Remove(f) 1711 if err != nil { 1712 t.Fatalf("Remove: %v", err) 1713 } 1714 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append") 1715 if s != "new&append" { 1716 t.Fatalf("writeFile: after append have %q want %q", s, "new&append") 1717 } 1718 s = writeFile(t, f, O_CREATE|O_RDWR, "old") 1719 if s != "old&append" { 1720 t.Fatalf("writeFile: after create have %q want %q", s, "old&append") 1721 } 1722 s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") 1723 if s != "new" { 1724 t.Fatalf("writeFile: after truncate have %q want %q", s, "new") 1725 } 1726 } 1727 1728 func TestStatDirWithTrailingSlash(t *testing.T) { 1729 // Create new temporary directory and arrange to clean it up. 1730 path, err := ioutil.TempDir("", "/_TestStatDirWithSlash_") 1731 if err != nil { 1732 t.Fatalf("TempDir: %s", err) 1733 } 1734 defer RemoveAll(path) 1735 1736 // Stat of path should succeed. 1737 _, err = Stat(path) 1738 if err != nil { 1739 t.Fatalf("stat %s failed: %s", path, err) 1740 } 1741 1742 // Stat of path+"/" should succeed too. 1743 path += "/" 1744 _, err = Stat(path) 1745 if err != nil { 1746 t.Fatalf("stat %s failed: %s", path, err) 1747 } 1748 } 1749 1750 func TestNilProcessStateString(t *testing.T) { 1751 var ps *ProcessState 1752 s := ps.String() 1753 if s != "<nil>" { 1754 t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>") 1755 } 1756 } 1757 1758 func TestSameFile(t *testing.T) { 1759 defer chtmpdir(t)() 1760 fa, err := Create("a") 1761 if err != nil { 1762 t.Fatalf("Create(a): %v", err) 1763 } 1764 defer Remove(fa.Name()) 1765 fa.Close() 1766 fb, err := Create("b") 1767 if err != nil { 1768 t.Fatalf("Create(b): %v", err) 1769 } 1770 defer Remove(fb.Name()) 1771 fb.Close() 1772 1773 ia1, err := Stat("a") 1774 if err != nil { 1775 t.Fatalf("Stat(a): %v", err) 1776 } 1777 ia2, err := Stat("a") 1778 if err != nil { 1779 t.Fatalf("Stat(a): %v", err) 1780 } 1781 if !SameFile(ia1, ia2) { 1782 t.Errorf("files should be same") 1783 } 1784 1785 ib, err := Stat("b") 1786 if err != nil { 1787 t.Fatalf("Stat(b): %v", err) 1788 } 1789 if SameFile(ia1, ib) { 1790 t.Errorf("files should be different") 1791 } 1792 } 1793 1794 func TestDevNullFile(t *testing.T) { 1795 f, err := Open(DevNull) 1796 if err != nil { 1797 t.Fatalf("Open(%s): %v", DevNull, err) 1798 } 1799 defer f.Close() 1800 fi, err := f.Stat() 1801 if err != nil { 1802 t.Fatalf("Stat(%s): %v", DevNull, err) 1803 } 1804 name := filepath.Base(DevNull) 1805 if fi.Name() != name { 1806 t.Fatalf("wrong file name have %v want %v", fi.Name(), name) 1807 } 1808 if fi.Size() != 0 { 1809 t.Fatalf("wrong file size have %d want 0", fi.Size()) 1810 } 1811 } 1812 1813 var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output") 1814 1815 func TestLargeWriteToConsole(t *testing.T) { 1816 if !*testLargeWrite { 1817 t.Skip("skipping console-flooding test; enable with -large_write") 1818 } 1819 b := make([]byte, 32000) 1820 for i := range b { 1821 b[i] = '.' 1822 } 1823 b[len(b)-1] = '\n' 1824 n, err := Stdout.Write(b) 1825 if err != nil { 1826 t.Fatalf("Write to os.Stdout failed: %v", err) 1827 } 1828 if n != len(b) { 1829 t.Errorf("Write to os.Stdout should return %d; got %d", len(b), n) 1830 } 1831 n, err = Stderr.Write(b) 1832 if err != nil { 1833 t.Fatalf("Write to os.Stderr failed: %v", err) 1834 } 1835 if n != len(b) { 1836 t.Errorf("Write to os.Stderr should return %d; got %d", len(b), n) 1837 } 1838 } 1839 1840 func TestStatDirModeExec(t *testing.T) { 1841 const mode = 0111 1842 1843 path, err := ioutil.TempDir("", "go-build") 1844 if err != nil { 1845 t.Fatalf("Failed to create temp directory: %v", err) 1846 } 1847 defer RemoveAll(path) 1848 1849 if err := Chmod(path, 0777); err != nil { 1850 t.Fatalf("Chmod %q 0777: %v", path, err) 1851 } 1852 1853 dir, err := Stat(path) 1854 if err != nil { 1855 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err) 1856 } 1857 if dir.Mode()&mode != mode { 1858 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode()&mode, mode) 1859 } 1860 } 1861 1862 func TestStatStdin(t *testing.T) { 1863 switch runtime.GOOS { 1864 case "android", "plan9": 1865 t.Skipf("%s doesn't have /bin/sh", runtime.GOOS) 1866 } 1867 1868 testenv.MustHaveExec(t) 1869 1870 if Getenv("GO_WANT_HELPER_PROCESS") == "1" { 1871 st, err := Stdin.Stat() 1872 if err != nil { 1873 t.Fatalf("Stat failed: %v", err) 1874 } 1875 fmt.Println(st.Mode() & ModeNamedPipe) 1876 Exit(0) 1877 } 1878 1879 fi, err := Stdin.Stat() 1880 if err != nil { 1881 t.Fatal(err) 1882 } 1883 switch mode := fi.Mode(); { 1884 case mode&ModeCharDevice != 0: 1885 case mode&ModeNamedPipe != 0: 1886 default: 1887 t.Fatalf("unexpected Stdin mode (%v), want ModeCharDevice or ModeNamedPipe", mode) 1888 } 1889 1890 var cmd *osexec.Cmd 1891 if runtime.GOOS == "windows" { 1892 cmd = osexec.Command("cmd", "/c", "echo output | "+Args[0]+" -test.run=TestStatStdin") 1893 } else { 1894 cmd = osexec.Command("/bin/sh", "-c", "echo output | "+Args[0]+" -test.run=TestStatStdin") 1895 } 1896 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1") 1897 1898 output, err := cmd.CombinedOutput() 1899 if err != nil { 1900 t.Fatalf("Failed to spawn child process: %v %q", err, string(output)) 1901 } 1902 1903 // result will be like "prw-rw-rw" 1904 if len(output) < 1 || output[0] != 'p' { 1905 t.Fatalf("Child process reports stdin is not pipe '%v'", string(output)) 1906 } 1907 } 1908 1909 func TestStatRelativeSymlink(t *testing.T) { 1910 testenv.MustHaveSymlink(t) 1911 1912 tmpdir, err := ioutil.TempDir("", "TestStatRelativeSymlink") 1913 if err != nil { 1914 t.Fatal(err) 1915 } 1916 defer RemoveAll(tmpdir) 1917 1918 target := filepath.Join(tmpdir, "target") 1919 f, err := Create(target) 1920 if err != nil { 1921 t.Fatal(err) 1922 } 1923 defer f.Close() 1924 1925 st, err := f.Stat() 1926 if err != nil { 1927 t.Fatal(err) 1928 } 1929 1930 link := filepath.Join(tmpdir, "link") 1931 err = Symlink(filepath.Base(target), link) 1932 if err != nil { 1933 t.Fatal(err) 1934 } 1935 1936 st1, err := Stat(link) 1937 if err != nil { 1938 t.Fatal(err) 1939 } 1940 1941 if !SameFile(st, st1) { 1942 t.Error("Stat doesn't follow relative symlink") 1943 } 1944 1945 if runtime.GOOS == "windows" { 1946 Remove(link) 1947 err = Symlink(target[len(filepath.VolumeName(target)):], link) 1948 if err != nil { 1949 t.Fatal(err) 1950 } 1951 1952 st1, err := Stat(link) 1953 if err != nil { 1954 t.Fatal(err) 1955 } 1956 1957 if !SameFile(st, st1) { 1958 t.Error("Stat doesn't follow relative symlink") 1959 } 1960 } 1961 } 1962 1963 func TestReadAtEOF(t *testing.T) { 1964 f := newFile("TestReadAtEOF", t) 1965 defer Remove(f.Name()) 1966 defer f.Close() 1967 1968 _, err := f.ReadAt(make([]byte, 10), 0) 1969 switch err { 1970 case io.EOF: 1971 // all good 1972 case nil: 1973 t.Fatalf("ReadAt succeeded") 1974 default: 1975 t.Fatalf("ReadAt failed: %s", err) 1976 } 1977 } 1978 1979 func TestLongPath(t *testing.T) { 1980 tmpdir := newDir("TestLongPath", t) 1981 defer func(d string) { 1982 if err := RemoveAll(d); err != nil { 1983 t.Fatalf("RemoveAll failed: %v", err) 1984 } 1985 }(tmpdir) 1986 1987 // Test the boundary of 247 and fewer bytes (normal) and 248 and more bytes (adjusted). 1988 sizes := []int{247, 248, 249, 400} 1989 for len(tmpdir) < 400 { 1990 tmpdir += "/dir3456789" 1991 } 1992 for _, sz := range sizes { 1993 t.Run(fmt.Sprintf("length=%d", sz), func(t *testing.T) { 1994 sizedTempDir := tmpdir[:sz-1] + "x" // Ensure it does not end with a slash. 1995 1996 // The various sized runs are for this call to trigger the boundary 1997 // condition. 1998 if err := MkdirAll(sizedTempDir, 0755); err != nil { 1999 t.Fatalf("MkdirAll failed: %v", err) 2000 } 2001 data := []byte("hello world\n") 2002 if err := ioutil.WriteFile(sizedTempDir+"/foo.txt", data, 0644); err != nil { 2003 t.Fatalf("ioutil.WriteFile() failed: %v", err) 2004 } 2005 if err := Rename(sizedTempDir+"/foo.txt", sizedTempDir+"/bar.txt"); err != nil { 2006 t.Fatalf("Rename failed: %v", err) 2007 } 2008 mtime := time.Now().Truncate(time.Minute) 2009 if err := Chtimes(sizedTempDir+"/bar.txt", mtime, mtime); err != nil { 2010 t.Fatalf("Chtimes failed: %v", err) 2011 } 2012 names := []string{"bar.txt"} 2013 if testenv.HasSymlink() { 2014 if err := Symlink(sizedTempDir+"/bar.txt", sizedTempDir+"/symlink.txt"); err != nil { 2015 t.Fatalf("Symlink failed: %v", err) 2016 } 2017 names = append(names, "symlink.txt") 2018 } 2019 if testenv.HasLink() { 2020 if err := Link(sizedTempDir+"/bar.txt", sizedTempDir+"/link.txt"); err != nil { 2021 t.Fatalf("Link failed: %v", err) 2022 } 2023 names = append(names, "link.txt") 2024 } 2025 for _, wantSize := range []int64{int64(len(data)), 0} { 2026 for _, name := range names { 2027 path := sizedTempDir + "/" + name 2028 dir, err := Stat(path) 2029 if err != nil { 2030 t.Fatalf("Stat(%q) failed: %v", path, err) 2031 } 2032 filesize := size(path, t) 2033 if dir.Size() != filesize || filesize != wantSize { 2034 t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize) 2035 } 2036 err = Chmod(path, dir.Mode()) 2037 if err != nil { 2038 t.Fatalf("Chmod(%q) failed: %v", path, err) 2039 } 2040 } 2041 if err := Truncate(sizedTempDir+"/bar.txt", 0); err != nil { 2042 t.Fatalf("Truncate failed: %v", err) 2043 } 2044 } 2045 }) 2046 } 2047 } 2048 2049 func testKillProcess(t *testing.T, processKiller func(p *Process)) { 2050 testenv.MustHaveExec(t) 2051 2052 // Re-exec the test binary itself to emulate "sleep 1". 2053 cmd := osexec.Command(Args[0], "-test.run", "TestSleep") 2054 err := cmd.Start() 2055 if err != nil { 2056 t.Fatalf("Failed to start test process: %v", err) 2057 } 2058 go func() { 2059 time.Sleep(100 * time.Millisecond) 2060 processKiller(cmd.Process) 2061 }() 2062 err = cmd.Wait() 2063 if err == nil { 2064 t.Errorf("Test process succeeded, but expected to fail") 2065 } 2066 } 2067 2068 // TestSleep emulates "sleep 1". It is a helper for testKillProcess, so we 2069 // don't have to rely on an external "sleep" command being available. 2070 func TestSleep(t *testing.T) { 2071 if testing.Short() { 2072 t.Skip("Skipping in short mode") 2073 } 2074 time.Sleep(time.Second) 2075 } 2076 2077 func TestKillStartProcess(t *testing.T) { 2078 testKillProcess(t, func(p *Process) { 2079 err := p.Kill() 2080 if err != nil { 2081 t.Fatalf("Failed to kill test process: %v", err) 2082 } 2083 }) 2084 } 2085 2086 func TestGetppid(t *testing.T) { 2087 if runtime.GOOS == "plan9" { 2088 // TODO: golang.org/issue/8206 2089 t.Skipf("skipping test on plan9; see issue 8206") 2090 } 2091 2092 testenv.MustHaveExec(t) 2093 2094 if Getenv("GO_WANT_HELPER_PROCESS") == "1" { 2095 fmt.Print(Getppid()) 2096 Exit(0) 2097 } 2098 2099 cmd := osexec.Command(Args[0], "-test.run=TestGetppid") 2100 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1") 2101 2102 // verify that Getppid() from the forked process reports our process id 2103 output, err := cmd.CombinedOutput() 2104 if err != nil { 2105 t.Fatalf("Failed to spawn child process: %v %q", err, string(output)) 2106 } 2107 2108 childPpid := string(output) 2109 ourPid := fmt.Sprintf("%d", Getpid()) 2110 if childPpid != ourPid { 2111 t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid) 2112 } 2113 } 2114 2115 func TestKillFindProcess(t *testing.T) { 2116 testKillProcess(t, func(p *Process) { 2117 p2, err := FindProcess(p.Pid) 2118 if err != nil { 2119 t.Fatalf("Failed to find test process: %v", err) 2120 } 2121 err = p2.Kill() 2122 if err != nil { 2123 t.Fatalf("Failed to kill test process: %v", err) 2124 } 2125 }) 2126 } 2127 2128 var nilFileMethodTests = []struct { 2129 name string 2130 f func(*File) error 2131 }{ 2132 {"Chdir", func(f *File) error { return f.Chdir() }}, 2133 {"Close", func(f *File) error { return f.Close() }}, 2134 {"Chmod", func(f *File) error { return f.Chmod(0) }}, 2135 {"Chown", func(f *File) error { return f.Chown(0, 0) }}, 2136 {"Read", func(f *File) error { _, err := f.Read(make([]byte, 0)); return err }}, 2137 {"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }}, 2138 {"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }}, 2139 {"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }}, 2140 {"Seek", func(f *File) error { _, err := f.Seek(0, io.SeekStart); return err }}, 2141 {"Stat", func(f *File) error { _, err := f.Stat(); return err }}, 2142 {"Sync", func(f *File) error { return f.Sync() }}, 2143 {"Truncate", func(f *File) error { return f.Truncate(0) }}, 2144 {"Write", func(f *File) error { _, err := f.Write(make([]byte, 0)); return err }}, 2145 {"WriteAt", func(f *File) error { _, err := f.WriteAt(make([]byte, 0), 0); return err }}, 2146 {"WriteString", func(f *File) error { _, err := f.WriteString(""); return err }}, 2147 } 2148 2149 // Test that all File methods give ErrInvalid if the receiver is nil. 2150 func TestNilFileMethods(t *testing.T) { 2151 for _, tt := range nilFileMethodTests { 2152 var file *File 2153 got := tt.f(file) 2154 if got != ErrInvalid { 2155 t.Errorf("%v should fail when f is nil; got %v", tt.name, got) 2156 } 2157 } 2158 } 2159 2160 func mkdirTree(t *testing.T, root string, level, max int) { 2161 if level >= max { 2162 return 2163 } 2164 level++ 2165 for i := 'a'; i < 'c'; i++ { 2166 dir := filepath.Join(root, string(i)) 2167 if err := Mkdir(dir, 0700); err != nil { 2168 t.Fatal(err) 2169 } 2170 mkdirTree(t, dir, level, max) 2171 } 2172 } 2173 2174 // Test that simultaneous RemoveAll do not report an error. 2175 // As long as it gets removed, we should be happy. 2176 func TestRemoveAllRace(t *testing.T) { 2177 if runtime.GOOS == "windows" { 2178 // Windows has very strict rules about things like 2179 // removing directories while someone else has 2180 // them open. The racing doesn't work out nicely 2181 // like it does on Unix. 2182 t.Skip("skipping on windows") 2183 } 2184 2185 n := runtime.GOMAXPROCS(16) 2186 defer runtime.GOMAXPROCS(n) 2187 root, err := ioutil.TempDir("", "issue") 2188 if err != nil { 2189 t.Fatal(err) 2190 } 2191 mkdirTree(t, root, 1, 6) 2192 hold := make(chan struct{}) 2193 var wg sync.WaitGroup 2194 for i := 0; i < 4; i++ { 2195 wg.Add(1) 2196 go func() { 2197 defer wg.Done() 2198 <-hold 2199 err := RemoveAll(root) 2200 if err != nil { 2201 t.Errorf("unexpected error: %T, %q", err, err) 2202 } 2203 }() 2204 } 2205 close(hold) // let workers race to remove root 2206 wg.Wait() 2207 } 2208 2209 // Test that reading from a pipe doesn't use up a thread. 2210 func TestPipeThreads(t *testing.T) { 2211 switch runtime.GOOS { 2212 case "freebsd": 2213 t.Skip("skipping on FreeBSD; issue 19093") 2214 case "solaris": 2215 t.Skip("skipping on Solaris; issue 19111") 2216 case "windows": 2217 t.Skip("skipping on Windows; issue 19098") 2218 case "plan9": 2219 t.Skip("skipping on Plan 9; does not support runtime poller") 2220 } 2221 2222 threads := 100 2223 2224 // OpenBSD has a low default for max number of files. 2225 if runtime.GOOS == "openbsd" { 2226 threads = 50 2227 } 2228 2229 r := make([]*File, threads) 2230 w := make([]*File, threads) 2231 for i := 0; i < threads; i++ { 2232 rp, wp, err := Pipe() 2233 if err != nil { 2234 for j := 0; j < i; j++ { 2235 r[j].Close() 2236 w[j].Close() 2237 } 2238 t.Fatal(err) 2239 } 2240 r[i] = rp 2241 w[i] = wp 2242 } 2243 2244 defer debug.SetMaxThreads(debug.SetMaxThreads(threads / 2)) 2245 2246 creading := make(chan bool, threads) 2247 cdone := make(chan bool, threads) 2248 for i := 0; i < threads; i++ { 2249 go func(i int) { 2250 var b [1]byte 2251 creading <- true 2252 if _, err := r[i].Read(b[:]); err != nil { 2253 t.Error(err) 2254 } 2255 if err := r[i].Close(); err != nil { 2256 t.Error(err) 2257 } 2258 cdone <- true 2259 }(i) 2260 } 2261 2262 for i := 0; i < threads; i++ { 2263 <-creading 2264 } 2265 2266 // If we are still alive, it means that the 100 goroutines did 2267 // not require 100 threads. 2268 2269 for i := 0; i < threads; i++ { 2270 if _, err := w[i].Write([]byte{0}); err != nil { 2271 t.Error(err) 2272 } 2273 if err := w[i].Close(); err != nil { 2274 t.Error(err) 2275 } 2276 <-cdone 2277 } 2278 } 2279 2280 func TestDoubleCloseError(t *testing.T) { 2281 path := sfdir + "/" + sfname 2282 file, err := Open(path) 2283 if err != nil { 2284 t.Fatal(err) 2285 } 2286 if err := file.Close(); err != nil { 2287 t.Fatalf("unexpected error from Close: %v", err) 2288 } 2289 if err := file.Close(); err == nil { 2290 t.Error("second Close did not fail") 2291 } else if pe, ok := err.(*PathError); !ok { 2292 t.Errorf("second Close returned unexpected error type %T; expected os.PathError", pe) 2293 } else if pe.Err != ErrClosed { 2294 t.Errorf("second Close returned %q, wanted %q", err, ErrClosed) 2295 } else { 2296 t.Logf("second close returned expected error %q", err) 2297 } 2298 }